NO

Author Topic: Inlining functions  (Read 9753 times)

Offline PaoloC13

  • Member
  • *
  • Posts: 44
Inlining functions
« on: June 21, 2016, 04:42:46 AM »

Hello, here is my code:

Code: [Select]
///////////////////////////////////////////////////////////
// Vertex.h

#pragma once

typedef struct CVertex {
float m_w[3];
} CVertex;

inline void CVertex_Copy(CVertex *this, const CVertex *pVertex); // Ok! defined in Vertex.c
inline void CVertex_SetX(CVertex *this, const float x) { this->m_w[0] = x; } // Declared and defined here!


///////////////////////////////////////////////////////////
// Vertex.c

#include "main.h"

inline void CVertex_Copy(CVertex *this, const CVertex *pVertex)
{
this->m_w[0] = pVertex->m_w[0];
this->m_w[1] = pVertex->m_w[1];
this->m_w[2] = pVertex->m_w[2];
}


...now, functions like CVertex_SetX declared and defined in a header file, will give me a "multiply defined symbols" error (!).
My question is: the inline-declared CVertex_Copy function is defined inside the implementation file. Will it still be inlined as if defined in the header?



Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Inlining functions
« Reply #1 on: June 21, 2016, 09:26:32 AM »
The inlining request is a proposal to the compiler, that can decide to act differently, and it can also create the standalone function anyway (maybe you are also using /Ob0 compiler flag?). This leads to the creation of a copy of the function in each module where you included the header.
When the functions to be inlined are defined in a header they are normally declared static for this exact purpose.
Try to define them this way:
Code: [Select]
static __inline void CVertex_Copy(CVertex *this, const CVertex *pVertex); // Ok! defined in Vertex.c
static __inline void CVertex_SetX(CVertex *this, const float x) { this->m_w[0] = x; } // Declared and defined here!
If you want the compiler to use only the inlined version use __forceinline instead of __inline.
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline PaoloC13

  • Member
  • *
  • Posts: 44
Re: Inlining functions
« Reply #2 on: June 22, 2016, 05:01:47 AM »
Sorry, I think I've done something wrong.

The inlining flag was -Ob1 (default). At the end of everything, the multiply defined symbols were due to some function definitions in headers that were not prefixed by the inline specifier.

Furthermore, other errors abaut "unresolved external symbol" were caused by inline declared function which were defined in the source file. I do not understand why! ...because other comparable cases of so coded function didn't provide such error.
I solved it by placing the definition in the header.

Thanks for your suggestions

Offline PaoloC13

  • Member
  • *
  • Posts: 44
...
« Reply #3 on: June 22, 2016, 05:22:41 AM »
There's a question I wanted to ask for a long time:

how can I do to see the assembly generated by, or corresponding to, a specific portion of my C code?

Scripter

  • Guest
Re: ...
« Reply #4 on: June 22, 2016, 06:20:16 AM »
There's a question I wanted to ask for a long time:

how can I do to see the assembly generated by, or corresponding to, a specific portion of my C code?

Open the project settings...

For 32 bit projects ....  Compiler Debug Info = None, Linker = Codeview and Coff
For 64 bit projects ....  Compiler Debug Info = None, Linker = Codeview

Click "Go Debug" on the tool bar.  It will index the program's entry point and you can scan down with the scroll bar to find what you want.

Scripter

  • Guest
Re: Inlining functions
« Reply #5 on: June 22, 2016, 06:33:21 AM »
Sorry, I think I've done something wrong.

The inlining flag was -Ob1 (default). At the end of everything, the multiply defined symbols were due to some function definitions in headers that were not prefixed by the inline specifier.

That would be a same name, different features problem... Prototypes must always match the function itself.

Quote
Furthermore, other errors abaut "unresolved external symbol" were caused by inline declared function which were defined in the source file. I do not understand why! ...because other comparable cases of so coded function didn't provide such error.
I solved it by placing the definition in the header.

Thanks for your suggestions

The unresolved external symbol error most often comes from the linker not being able to find the function.
Often as not it's a matter of calling conventions... _cdecl, _stdcall, or _fastcall ... selected in the project options.

As a general rule, when including Windows you should set your project's calling convention to StdCall for 32 bit projects and FastCall for 64 bit.

When you are working in pure c (i.e. not including Windows) you can use Cdecl for 32 bits and fastCall for 64 bit projects.

The main function in console programs will have to be defined specifying _cdecl calling convention to avoid errors.

Also in project options you should check the "Enable Pelles C extensions" box.
If you are including Windows, also enable the "Enable Windows extensions" checkbox.




Offline PaoloC13

  • Member
  • *
  • Posts: 44
Re: Inlining functions
« Reply #6 on: June 22, 2016, 07:49:57 AM »
As a general rule, when including Windows you should set your project's calling convention to StdCall for 32 bit projects and FastCall for 64 bit.

When you are working in pure c (i.e. not including Windows) you can use Cdecl for 32 bits and fastCall for 64 bit projects.

The main function in console programs will have to be defined specifying _cdecl calling convention to avoid errors.

Also in project options you should check the "Enable Pelles C extensions" box.
If you are including Windows, also enable the "Enable Windows extensions" checkbox.

Ok, therefore all my settings were right. I just add the "Enable Pelles C extensions".

Offline PaoloC13

  • Member
  • *
  • Posts: 44
Re: ...
« Reply #7 on: June 22, 2016, 08:19:52 AM »
Open the project settings...

For 32 bit projects ....  Compiler Debug Info = None, Linker = Codeview and Coff
For 64 bit projects ....  Compiler Debug Info = None, Linker = Codeview

Click "Go Debug" on the tool bar.  It will index the program's entry point and you can scan down with the scroll bar to find what you want.

Great! I can find the symbol of my functions and it's assebly.
But unfortunately the code of an inlined function disappears or blends in this stream of code.

Can this screen be saved as a text file?

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Inlining functions
« Reply #8 on: June 22, 2016, 11:03:17 AM »
With version 8 you can try this Add-In here
May the source be with you

Scripter

  • Guest
Re: ...
« Reply #9 on: June 22, 2016, 05:36:55 PM »
Open the project settings...

For 32 bit projects ....  Compiler Debug Info = None, Linker = Codeview and Coff
For 64 bit projects ....  Compiler Debug Info = None, Linker = Codeview

Click "Go Debug" on the tool bar.  It will index the program's entry point and you can scan down with the scroll bar to find what you want.

Great! I can find the symbol of my functions and it's assebly.
But unfortunately the code of an inlined function disappears or blends in this stream of code.

Yes it does... that's what inlining is about.

But you should know that it's not the great panacea some people claim it is. All it really saves you is the few CPU cycles necessary to call it as a function.  Moreover; with multiple copies of the code scattered all through your programs, debugging can become something of a nightmare if it works in one place but not another. 

While it is good to understand the concept, you should know that it seldom brings the benefits it promises.

Offline PaoloC13

  • Member
  • *
  • Posts: 44
Re: Inlining functions
« Reply #10 on: July 04, 2016, 04:11:58 PM »
With version 8 you can try this Add-In here

hello TimoVJL, thanks for the hint.
I have downloaded the DbgDisAsm_WS_a1 Add-In, I put the DbgDisAsm64.dll in the \PellesC\Bin\AddIns64 folder, but now I don't know what to do.

Offline PaoloC13

  • Member
  • *
  • Posts: 44
Re: ...
« Reply #11 on: July 04, 2016, 04:29:11 PM »
While it is good to understand the concept, you should know that it seldom brings the benefits it promises.

Yes I agree.
I use inlining with those functions that contain a simple instruction and are expected to be called inside a loop with a large number of iteractions, and in which I would ensure an excellent performance.

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Inlining functions
« Reply #12 on: July 04, 2016, 05:07:51 PM »
From menu Tools -> Customize -> AddIns check 'description of DbgTest1'
Then when at break in debugger, choose from menu Debug -> Debug Test 1
Result is seen at Output window.
May the source be with you

Scripter

  • Guest
Re: ...
« Reply #13 on: July 04, 2016, 11:05:15 PM »
While it is good to understand the concept, you should know that it seldom brings the benefits it promises.

Yes I agree.
I use inlining with those functions that contain a simple instruction and are expected to be called inside a loop with a large number of iteractions, and in which I would ensure an excellent performance.

 ;D Be careful not to fall into the trap of "Premature Optimization", a common affliction among programmers. I've seen guys spend literally months shaving a few milliseconds off a function that runs basically once per program... it's a total waste of time and effort in most cases. Unless you have something like high throughput real time processing going on a few milliseconds here and there will make no difference at all. It is far more important to write concise and easily maintainable source code than it will ever be to shave .001% off a program's run time.

Plus on modern computers there is another consideration called "Tight Loops". These are basically loops that don't allow the multitasker to switch.  For example:
Code: [Select]
while(*data)
    {
      while(-- *data);
      ++data;
    }
... this little loop which does nothing but count each byte of memory down to 0, when applied to a large enough data field, will slam your CPU usage right over to 100% and if it goes on long enough it might actually overheat and damage some CPUs with marginal heat sinks on them.

Given that a simple modification such as including Windows and ...
Code: [Select]
while(*data)
    {
      while(*data) --*data;
      ++data;
      Sleep(0);
    }
... could save you from a burned out computer, I'd say the small performance hit is worth it.

In other words... it's not all about "the fastest code" or "the best tricks", it's also about safety, stability and maintainability.


« Last Edit: July 05, 2016, 01:03:28 AM by Scripter »

Offline PaoloC13

  • Member
  • *
  • Posts: 44
Re: Inlining functions
« Reply #14 on: July 06, 2016, 03:19:42 AM »
From menu Tools -> Customize -> AddIns check 'description of DbgTest1'
Then when at break in debugger, choose from menu Debug -> Debug Test 1
Result is seen at Output window.

Perfect! Your indication matches, and I was able to see how it works.
Thank you!