static inline functions and gcc

M

mowgli

Hi,
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.

The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code

/** \brief Scaled Legendre Polynomial Order 0 */
static inline void Legendre0( double * value, void ** info )
{
(* value) = FAC0;
}
/** \brief Scaled Legendre Polynomial Order 1 */
static inline void Legendre1( double * value, void ** info )
{
(* value) = FAC1 * ( *( (double *) info[0]) );
}
FAC0 and FAC1 are constants. This continues until Legendre6 ( ). I
also declare this

/** \brief Definition of the Set of Basis Functions */
LEGFunc LegendreBasis[7];

where LEGFunc itself is
typedef void (* LEGFunc) (void * item, void ** data);

Then in the file Legendre.c there is
/** \brief Defines the Legendre Basis up to 6th order. */
LEGFunc LegendreBasis[7] =
{
(LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
(LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6
};

Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.

I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove the static which now doesn't have any
function anymore in any case. With static the linker gives the same
errors.

Can somebody explain this to me?
Thank you,
Sascha
 
F

Fred

Hi,
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.

The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code

/** \brief Scaled Legendre Polynomial Order 0 */
static inline void Legendre0( double * value, void ** info )
{
    (* value) = FAC0;}

/** \brief Scaled Legendre Polynomial Order 1 */
static inline void Legendre1( double * value, void ** info )
{
    (* value) = FAC1 * ( *( (double *) info[0]) );}

FAC0 and FAC1 are constants. This continues until Legendre6 ( ). I
also declare this

/** \brief Definition of the Set of Basis Functions */
LEGFunc LegendreBasis[7];

where LEGFunc itself is
typedef void (* LEGFunc) (void * item, void ** data);

Then in the file Legendre.c there is
/** \brief Defines the Legendre Basis up to 6th order. */
LEGFunc LegendreBasis[7] =
{
   (LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
   (LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6

};

Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.

I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove the static which now doesn't have any
function anymore in any case. With static the linker gives the same
errors.

Where did you move those functions FROM?
Did that file get compiled, and did you specify its object file to the
linker?
 
S

Stephen Sprunk

mowgli said:
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.

The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code

/** \brief Scaled Legendre Polynomial Order 0 */
static inline void Legendre0( double * value, void ** info )
{
(* value) = FAC0;
} ....

LEGFunc LegendreBasis[7] =
{
(LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
(LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6
};

Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.

I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove the static which now doesn't have any
function anymore in any case. With static the linker gives the same
errors.

Can somebody explain this to me?

A function should only be declared "static inline" if _all_ of the calls
to it can be inlined, because the compiler is not required to emit
standalone code for the function. Indirect calls, such as via your jump
table, cannot be inlined; only direct calls can be inlined.

MSVC apparently noticed you were doing something dangerous and silently
disabled its "inline static" optimization -- or it doesn't have GCC's
more aggressive optimization capabilities to begin with.

S
 
H

Harald van Dijk

Stephen said:
A function should only be declared "static inline" if _all_ of the calls
to it can be inlined, because the compiler is not required to emit
standalone code for the function. Indirect calls, such as via your jump
table, cannot be inlined; only direct calls can be inlined.

A compiler _is_ required to emit standalone code for the function, if there
are any references to it that cannot be inlined. The standard does not
specify any cases where the compiler is required to honour the keyword, not
even the most basic direct calls you can think of, so if you were right, it
would not be possible to use inline functions in any sensible way in a
standard C program.

I can't say anything directly about the original question, because it does
not give enough information, but pointers to static inline functions are
perfectly valid in C.
 
B

Barry Schwarz

Hi,
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.

The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code

/** \brief Scaled Legendre Polynomial Order 0 */
static inline void Legendre0( double * value, void ** info )
{
    (* value) = FAC0;}
snip

Then in the file Legendre.c there is
/** \brief Defines the Legendre Basis up to 6th order. */
LEGFunc LegendreBasis[7] =
{
   (LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
   (LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6

};

Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.

I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove the static which now doesn't have any
function anymore in any case. With static the linker gives the same
errors.

When you declare a function static, the funciton nameis not exported
from the compile phase to link phase. (I think the technical term is
internal linkage.)
 
M

mowgli

A compiler _is_ required to emit standalone code for the function, if there
are any references to it that cannot be inlined. The standard does not
specify any cases where the compiler is required to honour the keyword, not
even the most basic direct calls you can think of, so if you were right, it
would not be possible to useinlinefunctions in any sensible way in a
standard C program.

I can't say anything directly about the original question, because it does
not give enough information, but pointers to static inline functions are
perfectly valid in C.

Which other information do I have to provide?
Thanks in advance
 
M

mowgli

Hi,
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.
The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code
/** \brief Scaled Legendre Polynomial Order 0 */
staticinlinevoid Legendre0( double * value, void ** info )
{
    (* value) = FAC0;}
snip



Then in the file Legendre.c there is
/** \brief Defines the Legendre Basis up to 6th order. */
LEGFunc LegendreBasis[7] =
{
   (LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
   (LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6

Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.
I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove thestaticwhich now doesn't have any
function anymore in any case. Withstaticthe linker gives the same
errors.

When you declare a functionstatic, the funciton nameis not exported
from the compile phase to link phase.  (I think the technical term is
internal linkage.)

Can I force the export of the name?
 
B

Barry Schwarz

Hi,
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.
The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code
/** \brief Scaled Legendre Polynomial Order 0 */
staticinlinevoid Legendre0( double * value, void ** info )
{
    (* value) = FAC0;}
Then in the file Legendre.c there is
/** \brief Defines the Legendre Basis up to 6th order. */
LEGFunc LegendreBasis[7] =
{
   (LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
   (LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6
};
Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.
I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove thestaticwhich now doesn't have any
function anymore in any case. Withstaticthe linker gives the same
errors.
When you declare a functionstatic, the funciton nameis not exported
from the compile phase to link phase.  (I think the technical term is
internal linkage.)

Can I force the export of the name?

You did, by removing the static. The name of a static function will
never be visible to the linker
 
J

jameskuyper

mowgli said:
Which other information do I have to provide?

The definitions of FAC0 and FAC1 might be relevant.

The single most helpful thing you could provide would be the full text
of a version of your entire program that is as small and simple as
possible, contains everything it needs to contain in order to be
compiled, and produces the error message you're asking about when you
try to compile it. Then give use the exact command line you used to
compile it, and the exact text of the error message it produces.

Don't cut out anything that you think we don't need to know - since
you don't know what the problem is, the thing you've cut out is
disproportionately likely to be the thing we need to see in order to
identify the problem. Don't re-type any of it by hand - we don't want
to debug your typing errors. Cut and paste everything into your
message without modification.

In your case, if you've described the problem correctly, I suspect
that the simplified version will only need to contain FAC0, Legendre0
and LegendreBasis; it need not contain the other 6 functions and their
corresponding constants, and LegendreBasis can be shortened to be a
one-element array, and you probably don't need to include the code
that actually uses LegendreBasis. However, if you're describing the
problem incorrectly, the simplified version of your program might need
to be a little longer than that.
 
S

Stefan Ram

Harald van =?UTF-8?B?RMSzaw==?= said:
A compiler _is_ required to emit standalone code for the function, if there
are any references to it that cannot be inlined. The standard does not
specify any cases where the compiler is required to honour the keyword

Even if it would, the keyword »inline« does not mean at all
that the code should be /inlined/. »Making a function an inline
function suggests that calls to the function be as fast as
possible.« ISO/IEC 9899:1999 (E) 6.7.4#5. ¯¯¯¯¯¯¯¯¯¯
¯¯¯¯¯¯¯¯
(This is different from C++ IIRC.)
 
W

Willem

Richard wrote:
) But meanwhile in the real world removing the call (ie
) making it inline) is the best way to "fast as possible" in 99.9999999%
) of HW platforms I know of.

Suppose that the function is used in many places (say, one function uses it
20 times or so).

Suppose also that the function is reasonably large, but small enough to fit
in the processor cache a few times over. (say, less than 1/4 the size of
the cache)

Suppose also that the calling function (the one using it 20 times) doesn't
do that much else and is small enough to also fit in the processor cache
(say, less than 3/4 the size of the cache).

And lastly, suppose the function is a big loop, running hundreds of times.

Now, without inlining, the whole thing fits into the processor cache, so
the whole loop only needs to be fetched from memory once.

With inlining, it's dramatically larger than the cache and each time around
the whole loop will need to be fetched from memory.

Are you saying that only happens 0.0000001% of the time ?


PS: loop unrolling has this same issue. It's often a lot more
dramatic as the unrolling is in the order of L1 cache sizes.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
M

mowgli

The definitions of FAC0 and FAC1 might be relevant.

The single most helpful thing you could provide would be the full text
of a version of your entire program that is as small and simple as
possible, contains everything it needs to contain in order to be
compiled, and produces the error message you're asking about when you
try to compile it. Then give use the exact command line you used to
compile it, and the exact text of the error message it produces.

Don't cut out anything that you think we don't need to know - since
you don't know what the problem is, the thing you've cut out is
disproportionately likely to be the thing we need to see in order to
identify the problem. Don't re-type any of it by hand - we don't want
to debug your typing errors. Cut and paste everything into your
message without modification.

In your case, if you've described the problem correctly, I suspect
that the simplified version will only need to contain FAC0, Legendre0
and LegendreBasis; it need not contain the other 6 functions and their
corresponding constants, and LegendreBasis can be shortened to be a
one-element array, and you probably don't need to include the code
that actually uses LegendreBasis. However, if you're describing the
problem incorrectly, the simplified version of your program might need
to be a little longer than that.

Now i understand it even less because after making a minimal project,
the error is not there anymore.
I created three files: Legendre.h, Legendre.c, main.c

=======================================
Legendre.h:
#define FAC0 1.000000000000000

typedef void (* LEGFunc) (void * item, void ** data);

LEGFunc LegendreBasis[2];

static inline void Legendre0( double * value, void ** info )
{
(* value) = FAC0;
}

static inline void Legendre1( double * value, void ** info )
{
(* value) = FAC0;
}

=======================================

Legendre.c:
#include "Legendre.h"

LEGFunc LegendreBasis[2] =
{
(LEGFunc) Legendre0, (LEGFunc) Legendre1
};

=======================================

main.c:
#include "Legendre.h"

int main (int argc, char ** args)
{
double dValueX;
void * pinfoX;

LegendreBasis[0](&dValueX, &pinfoX);
LegendreBasis[1](&dValueX, &pinfoX);

return 0;
}

=======================================

and compiled with
gcc -O0 -g3 -Wall -c -o"Legendre.o" "Legendre.c"
gcc -O0 -g3 -Wall -c -o"main.o" "main.c"

and linked with
gcc -o"Legendre" ./Legendre.o ./main.o

which works...

Since i cannot reproduce the error in a simpler environment, i thank
you all for your help
Sascha
 
J

jameskuyper

mowgli said:
....
Now i understand it even less because after making a minimal project,
the error is not there anymore. ....
Since i cannot reproduce the error in a simpler environment, i thank
you all for your help

Don't give up now! When I said "as small as possible", that didn't
mean that you should cut it down so small that it no longer
demonstrates the problem. Start by making a copy of the original
program. Working on the copy (not the original!), cut out one piece at
a time, choosing pieces that you don't think are relevant to the
problem, making appropriate changes to the remaining parts of the
program. Start with the large pieces first, then go after smaller
ones. After each cut, recompile - if you don't get the same error
message, put that piece back in, and cut out another one instead. I
normally actually keep two versions: the simplest version that
produced the error message, and the one I'm currently testing - this
makes it easier to back out a change that turned off the error
message. Keep doing this until you can't find anything to cut that
doesn't also remove the error message. Then post the result here.

Note: in the process of cutting down the program, when you find out
which cuts work and which don't, it's quite likely that you will
figure out what the problem actually is, and therefore won't even need
to post a question here.
 
I

Ian Collins

Willem said:
Richard wrote:
) But meanwhile in the real world removing the call (ie
) making it inline) is the best way to "fast as possible" in 99.9999999%
) of HW platforms I know of.

Suppose that the function is used in many places (say, one function uses it
20 times or so).

Suppose also that the function is reasonably large, but small enough to fit
in the processor cache a few times over. (say, less than 1/4 the size of
the cache)

Suppose also that the calling function (the one using it 20 times) doesn't
do that much else and is small enough to also fit in the processor cache
(say, less than 3/4 the size of the cache).

And lastly, suppose the function is a big loop, running hundreds of times.

Now, without inlining, the whole thing fits into the processor cache, so
the whole loop only needs to be fetched from memory once.

With inlining, it's dramatically larger than the cache and each time around
the whole loop will need to be fetched from memory.

Are you saying that only happens 0.0000001% of the time ?

PS: loop unrolling has this same issue. It's often a lot more
dramatic as the unrolling is in the order of L1 cache sizes.

A good reason to use compilers witch support profile based optimisation!
 
I

Ian Collins

Stefan said:
Even if it would, the keyword »inline« does not mean at all
that the code should be /inlined/. »Making a function an inline
function suggests that calls to the function be as fast as
possible.« ISO/IEC 9899:1999 (E) 6.7.4#5. ¯¯¯¯¯¯¯¯¯¯
¯¯¯¯¯¯¯¯
(This is different from C++ IIRC.)

Not really, inline is just a hint in C++ as well.
 
K

Keith Thompson

mowgli said:
Now i understand it even less because after making a minimal project,
the error is not there anymore.

James gave you some good advice on this.
I created three files: Legendre.h, Legendre.c, main.c

=======================================
Legendre.h:
#define FAC0 1.000000000000000

typedef void (* LEGFunc) (void * item, void ** data);

LEGFunc LegendreBasis[2];

static inline void Legendre0( double * value, void ** info )
{
(* value) = FAC0;
}

static inline void Legendre1( double * value, void ** info )
{
(* value) = FAC0;
}

=======================================

Legendre.c:
#include "Legendre.h"

LEGFunc LegendreBasis[2] =
{
(LEGFunc) Legendre0, (LEGFunc) Legendre1
};

This is suspicious. You can convert from any pointer-to-function type
to any other pointer-to-function type (and a cast is required for such
a conversion), but you can call through such a pointer only if you
convert back to the actual type of the function.

Here you have an array of pointers to functions taking arguments of
types void* and void**, but you populate it with converted pointers to
functions taking arguments of type double* and void**. And later,
when you call the functions through the pointers, you don't convert
the function pointers; instead you (implicitly) convert the arguments
to the functions.

It's very likely that this isn't the cause of whatever problem you're
actually seeing. As long as double* and void* have the same
representation and are passed as arguments in the same way, it will
*probably* "work". But strictly speaking the behavior is undefined.

From the pared-down code you've posted, I don't see any reason not
to declare

typedef void (* LEGFunc) (double * item, void ** data);

and drop the casts in the initialization of LegendreBasis.

If, in your real code, LegendreBasis actually needs to be
heterogeneous, you should keep track of the actual type of each entry
and convert back to that type before making an indirect call.

[snip]
 
S

Stefan Ram

Ian Collins said:
Not really, inline is just a hint in C++ as well.

In C, it hints to make the call /as fast as possible/.

In C++, the »inline specifier indicates to the implementation
that /inline substitution/ of the function body at the point of
call is to be preferred to the usual function call mechanism.«
(ISO/IEC 14882:2003(E) 7.1.2p2).

The difference exists between /as fast as possible/ in C and
/inline substitution/ in C++.
 
I

Ian Collins

Stefan said:
In C, it hints to make the call /as fast as possible/.

In C++, the »inline specifier indicates to the implementation
that /inline substitution/ of the function body at the point of
call is to be preferred to the usual function call mechanism.«
(ISO/IEC 14882:2003(E) 7.1.2p2).

The difference exists between /as fast as possible/ in C and
/inline substitution/ in C++.
But the keyword is still just a hit in both cases.
 
M

mohangupta13

Hi,
maybe my problem is a well know thing but i recently switched from
developing under Visual Studio to Linux and gcc. I ported a medium
size project and after some time everything compiled but the linking
failed.

The code that caused the problem worked with VS and is the following:
I have header file called Legendre.h where is this code


are you really sure #inludeD "Legendre.h" in our original program. I
was being suspicious, these are small things but sometimes are cause
of major headache.





/** \brief Scaled Legendre Polynomial Order 0 */
static inline void Legendre0( double * value, void ** info )
{
(* value) = FAC0;}

/** \brief Scaled Legendre Polynomial Order 1 */
static inline void Legendre1( double * value, void ** info )
{
(* value) = FAC1 * ( *( (double *) info[0]) );}

FAC0 and FAC1 are constants. This continues until Legendre6 ( ). I
also declare this

/** \brief Definition of the Set of Basis Functions */
LEGFunc LegendreBasis[7];

where LEGFunc itself is
typedef void (* LEGFunc) (void * item, void ** data);

Then in the file Legendre.c there is
/** \brief Defines the Legendre Basis up to 6th order. */
LEGFunc LegendreBasis[7] =
{
(LEGFunc) Legendre0, (LEGFunc) Legendre1, (LEGFunc) Legendre2,
(LEGFunc) Legendre3,
(LEGFunc) Legendre4, (LEGFunc) Legendre5, (LEGFunc) Legendre6

};

Here i get an "undefined reference" error for Legendre0 - Legendre6. I
checked the Legendre.o object file with nm and there the Legendre
objects exist but are undefined.

I solved it by moving the Legendre0-6 functions into the Legendre.c
file and i had to remove the static which now doesn't have any
function anymore in any case. With static the linker gives the same
errors.

Can somebody explain this to me?
Thank you,
Sascha
 
B

Ben Bacarisse

mohangupta13 said:
are you really sure #inludeD "Legendre.h" in our original program. I
was being suspicious, these are small things but sometimes are cause
of major headache.

I am baffled. I can't find #inludeD in anything the OP posted. Was
your point about the capital 'L'?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top