Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > inline vs. function pointers

Reply
Thread Tools

inline vs. function pointers

 
 
copx
Guest
Posts: n/a
 
      01-27-2011
C99 gave us the "inline" keyword and IIRC in standard C
(as opposed to certain propriety dialects) it is just a hint
for the compiler i.e. there is no guarantee that a function
declared "inline" will actually be inlined all the time.

Now, here is the problem, a certain C compiler when evoked
in ANSI C mode produces an error message when I put
pointers to "inline" functions in an array of function pointers.
The compiler actually inlines the function code in this case, never
putting the functions themselves in the resulting binary and
thus renders the pointers invalid.

Is that standard conforming behavior? I mean, is there a
rule that you are not allowed to use pointers to "inline" functions?


 
Reply With Quote
 
 
 
 
Eric Sosman
Guest
Posts: n/a
 
      01-27-2011
On 1/27/2011 2:38 AM, copx wrote:
> C99 gave us the "inline" keyword and IIRC in standard C
> (as opposed to certain propriety dialects) it is just a hint for the
> compiler i.e. there is no guarantee that a function
> declared "inline" will actually be inlined all the time.
>
> Now, here is the problem, a certain C compiler when evoked
> in ANSI C mode produces an error message when I put
> pointers to "inline" functions in an array of function pointers.
> The compiler actually inlines the function code in this case, never
> putting the functions themselves in the resulting binary and
> thus renders the pointers invalid.
>
> Is that standard conforming behavior? I mean, is there a
> rule that you are not allowed to use pointers to "inline" functions?


Could you show a short (but complete and accurate!) sample
of the source code? And could you also exhibit the compiler's
complaint, instead of just describing it as "an error message?"

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)lid
 
Reply With Quote
 
 
 
 
dSpam@arcor.de
Guest
Posts: n/a
 
      01-27-2011
On 27 Jan., 08:38, "copx" <(E-Mail Removed)> wrote:
> Now, here is the problem, a certain C compiler when evoked
> in ANSI C mode produces an error message when I put
> pointers to "inline" functions in an array of function pointers.
> The compiler actually inlines the function code in this case, never
> putting the functions themselves in the resulting binary and
> thus renders the pointers invalid.
>
> Is that standard conforming behavior? I mean, is there a
> rule that you are not allowed to use pointers to "inline" functions?


The answer to the first question depends on the function's linkage.
The answer to the second question is "No".
 
Reply With Quote
 
copx
Guest
Posts: n/a
 
      01-27-2011


"Eric Sosman" wrote in message
news:ihrud5$vnm$(E-Mail Removed)-september.org...
>Could you show a short (but complete and accurate!) sample
>of the source code?


See below.

>And could you also exhibit the compiler's
>complaint, instead of just describing it as "an error message?"


Ok.

===== test.c =======

#include <stdio.h>

#define FIB_MAX 8000

typedef unsigned char BYTE;
typedef void (* const LSYSTEM[3])(BYTE **);

static void ls_init(BYTE *p) { *p = 1; *(p + 1) = 0; }
static inline void ls0(BYTE **p) { **p = 0; }
static inline void ls1(BYTE **p) { **p = 2; *p += 1;}
static inline void ls2(BYTE **p) { **p = 1; *p += 1; ls1(p);}


static BYTE Ls[2][FIB_MAX];


static unsigned int lsystem(unsigned int n)
{
BYTE *cur, *pre;
unsigned int dp = 0;

ls_init(Ls[0]);

do {
pre = Ls[dp]; cur = Ls[dp = !dp];

do {
static LSYSTEM l = {ls0, ls1, ls2};

l[*pre](&cur);

} while (*pre++);

} while (--n);

return cur - Ls[dp];
}


unsigned int fib(unsigned int n)
{
return n < 2 ? n : lsystem(--n);
}


int main(void)
{
unsigned int i;

for (i = 0; i < 21; i++) printf("F%u: %u\n", i, fib(i));

return 0;
}

========

gcc -Wall -Wextra -std=c99 -pedantic -O2 test.c
No warnings, compiles and runs as expected.

I suspect the compiler who chokes on this is buggy, but I am not
sure. Here's the output:

===
Warning d:\dev\test\test.c: 28 assignment of pointer to inline
function(pointer to pointer to unsigned char) to pointer to
void function(pointer to pointer to unsigned char)

Warning d:\dev\test\test.c: 28 assignment of pointer to inline
function(pointer to pointer to unsigned char) to pointer to
void function(pointer to pointer to unsigned char)

Warning d:\dev\test\test.c: 28 assignment of pointer to inline
function(pointer to pointer to unsigned char) to pointer to
void function(pointer to pointer to unsigned char)

Error test.obj: Undefined (*UND*). Symbol _ls0
=======

Putting "inline" in the LSYSTEM typedef eliminates the
warnings but not the error. Oh, and GCC seems to think "inline"
has no place in a typedef:

test.c:6:30: warning: typedef 'LSYSTEM' declared 'inline'

Good thing I don't usually use C99, so I don't have to worry
about such disagreements. This was just some experimental
code.

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      01-27-2011
"copx" <(E-Mail Removed)> writes:
[...]
> Putting "inline" in the LSYSTEM typedef eliminates the
> warnings but not the error. Oh, and GCC seems to think "inline"
> has no place in a typedef:
>
> test.c:6:30: warning: typedef 'LSYSTEM' declared 'inline'


I believe gcc is correct. "inline" is a function specifier (the only
one in the language).

C99 6.7.4p2:

Function specifiers shall be used only in the declaration of an
identifier for a function.

In other words, "inline" isn't part of the function type; it's an
attribute of an individual declared function.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
copx
Guest
Posts: n/a
 
      01-28-2011


"copx" wrote in message news:ihr7ej$irp$(E-Mail Removed)...
>>The compiler actually inlines the function code in this case, never
>>putting the functions themselves in the resulting binary and
>>thus renders the pointers invalid.
>>
>>Is that standard conforming behavior?


Answering my own question again: No.

C99 6.7.4
function specifier:
inline

"Likewise, the function has a single address, regardless of the number of
inline definitions that occur"

Oh well, another bug report.

 
Reply With Quote
 
jacob navia
Guest
Posts: n/a
 
      01-28-2011
Le 27/01/11 16:20, copx a écrit :
>
>
> "Eric Sosman" wrote in message
> news:ihrud5$vnm$(E-Mail Removed)-september.org...
>> Could you show a short (but complete and accurate!) sample
>> of the source code?

>
> See below.
>
>> And could you also exhibit the compiler's
>> complaint, instead of just describing it as "an error message?"

>
> Ok.
>
> ===== test.c =======
>
> #include <stdio.h>
>
> #define FIB_MAX 8000
>
> typedef unsigned char BYTE;
> typedef void (* const LSYSTEM[3])(BYTE **);
>
> static void ls_init(BYTE *p) { *p = 1; *(p + 1) = 0; }
> static inline void ls0(BYTE **p) { **p = 0; }
> static inline void ls1(BYTE **p) { **p = 2; *p += 1;}
> static inline void ls2(BYTE **p) { **p = 1; *p += 1; ls1(p);}
>
>
> static BYTE Ls[2][FIB_MAX];
>
>
> static unsigned int lsystem(unsigned int n)
> {
> BYTE *cur, *pre;
> unsigned int dp = 0;
>
> ls_init(Ls[0]);
>
> do {
> pre = Ls[dp]; cur = Ls[dp = !dp];
>
> do {
> static LSYSTEM l = {ls0, ls1, ls2};
>
> l[*pre](&cur);
>
> } while (*pre++);
>
> } while (--n);
>
> return cur - Ls[dp];
> }
>
>
> unsigned int fib(unsigned int n)
> {
> return n < 2 ? n : lsystem(--n);
> }
>
>
> int main(void)
> {
> unsigned int i;
>
> for (i = 0; i < 21; i++) printf("F%u: %u\n", i, fib(i));
>
> return 0;
> }
>
> ========
>
> gcc -Wall -Wextra -std=c99 -pedantic -O2 test.c
> No warnings, compiles and runs as expected.
>
> I suspect the compiler who chokes on this is buggy, but I am not
> sure. Here's the output:
>
> ===
> Warning d:\dev\test\test.c: 28 assignment of pointer to inline
> function(pointer to pointer to unsigned char) to pointer to
> void function(pointer to pointer to unsigned char)
>


Assigning function pointers with different characteristics will
always produce a warning.


>
> Error test.obj: Undefined (*UND*). Symbol _ls0



static inline functions generate no function address.
If you want the function address eliminate the static...

> =======
>
> Putting "inline" in the LSYSTEM typedef eliminates the
> warnings but not the error. Oh, and GCC seems to think "inline"
> has no place in a typedef:
>
> test.c:6:30: warning: typedef 'LSYSTEM' declared 'inline'
>
> Good thing I don't usually use C99, so I don't have to worry
> about such disagreements. This was just some experimental
> code.
>


I do not see what C99 has to do with this here. Anyway. I will wait
till the next standard appears to fix those bugs. Maybe they will
declare that optional...

 
Reply With Quote
 
jacob navia
Guest
Posts: n/a
 
      01-28-2011
Le 28/01/11 08:54, Ian Collins a écrit :
> On 01/28/11 08:37 PM, jacob navia wrote:
>> Le 27/01/11 16:20, copx a écrit :
>>> ========
>>>
>>> gcc -Wall -Wextra -std=c99 -pedantic -O2 test.c
>>> No warnings, compiles and runs as expected.
>>>
>>> I suspect the compiler who chokes on this is buggy, but I am not
>>> sure. Here's the output:
>>>
>>> ===
>>> Warning d:\dev\test\test.c: 28 assignment of pointer to inline
>>> function(pointer to pointer to unsigned char) to pointer to
>>> void function(pointer to pointer to unsigned char)
>>>

>>
>> Assigning function pointers with different characteristics will
>> always produce a warning.

>
> But they don't have different types.
>

Yes but they have different characteristics: one is inline and the other
is not inline.

This warning is crucial when you have _stdcall functions. And
_stdcall is a similar attribute like inline.

>>> Error test.obj: Undefined (*UND*). Symbol _ls0

>>
>> static inline functions generate no function address.
>> If you want the function address eliminate the static...

>
> Says who?
>


Me.

> All the standard says is "Making a function an inline function suggests
> that calls to the function be as fast as possible".
>

Yes, and I do not generate the code for it. Changing it is around
4-5 hours work including testing. I will do it when the next standard
appears, to be sure that inline is not declared optional.


 
Reply With Quote
 
copx
Guest
Posts: n/a
 
      01-28-2011


"jacob navia" wrote in message news:ihtrol$a0k$(E-Mail Removed)...
>Assigning function pointers with different characteristics will
>always produce a warning.


But the pointers aren't different because the function specifier
("inline") is not supposed to be part of the function pointer type.

All the following functions..

static inline void foo(void);
static void foo(void);
inline void foo(void);

... have the same function pointer type: void (*)(void)

... at least in ISO C.

>> Error test.obj: Undefined (*UND*). Symbol _ls0

>
>static inline functions generate no function address.


Is lcc a ISO C compiler or not? Because a conforming compiler
cannot simply decide that "static inline functions generate
no function address". IMO the standard is pretty clear about
the fact that you aren't allowed to optimize away the function
definitions here.

>> Good thing I don't usually use C99, so I don't have to worry
>> about such disagreements. This was just some experimental
>> code.

>
>I do not see what C99 has to do with this here.


The point is that IMO the behavior of your compiler does not
conform to the C99 standard here and I haven't had such problems
with C90 code yet. That standard is fully supported by basically
every piece of software which calls itself "a C compiler". C99
unfortunately isn't.

>Anyway. I will wait till the next standard appears to fix those bugs.
>Maybe they will declare that optional...


Your choice, cannot say I care much about this. I have just checked,
there aren't any big claims of conforming to ANY C standard
on the lccwin32 website, so it's ok I guess.

I can see why you want to stick to the current behavior. This
guaranteed inlining / function elemination behavior turns
static inline functions into full, type safe replacements for many
preprocessor macros. Also, not dealing with this particular
case (pointers to static inline functions) in a conforming way
probably simplifies the compiler logic.

I prefer ISO C compilers, though.

 
Reply With Quote
 
jacob navia
Guest
Posts: n/a
 
      01-28-2011
Le 28/01/11 11:46, copx a écrit :
>
>
> "jacob navia" wrote in message news:ihtrol$a0k$(E-Mail Removed)...
>> Assigning function pointers with different characteristics will
>> always produce a warning.

>
> But the pointers aren't different because the function specifier
> ("inline") is not supposed to be part of the function pointer type.
>
> All the following functions..
>
> static inline void foo(void);
> static void foo(void);
> inline void foo(void);
>
> .. have the same function pointer type: void (*)(void)
>
> .. at least in ISO C.
>


Yes, they have the same type.

But

int _stdcall fn(void);
and
int fn(void);

have also the same type but if you mix pointers to one with pointers to
the other a crash is guaranteed. So I always warn.

OK, I could spend hours "fixing" that warning and detecting that the
pointers are different because of the inline attribute and NOT because
of a _stdcall attribute or _noreturns or others.

Maybe one day I will do it, but before I have to do the correction for
the bad code generation that you pointed out. I am working already
6 hours in that problem and there is no solution in sight. I discovered
that if you write

dp = !dp;
ptr = table[dp];

the bug disappears. It is only when you write

ptr = table[dp = !dp];

that the bug manifests itself (only when optimizations are on).
And I will have for X hours more, I do not know.


> Your choice, cannot say I care much about this. I have just checked,
> there aren't any big claims of conforming to ANY C standard
> on the lccwin32 website, so it's ok I guess.
>
> I can see why you want to stick to the current behavior. This
> guaranteed inlining / function elemination behavior turns
> static inline functions into full, type safe replacements for many
> preprocessor macros. Also, not dealing with this particular case
> (pointers to static inline functions) in a conforming way
> probably simplifies the compiler logic.
>


Well, yes. I would have to detect when a function pointer is being
used. Then, realize that it is a pointer to an inline function. Then
I would have to add some annotation to the inline function pointer
symbol to generate ts code anyway.

WITHOUT INTRODUCING ANY NEW BUGS...

This is something like 1 day of work...

> I prefer ISO C compilers, though.
>


I have been working for this project for 12 years or more. I have
financed all expenses and all my work. But I can't do more than what I
do now. If you would buy a maintenance contract you would be served
quickly. But you didn't.

jacob
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointers, pointers, pointers... cerr C Programming 12 04-07-2011 11:17 PM
How to know the inline-function was implemented the inline way or normal way? ypjofficial@indiatimes.com C++ 7 07-18-2006 11:22 PM
forcing compiler to consider inline function inline. Ajay C++ 5 04-01-2006 02:03 PM
Use of inline function in inline function - is it allowed? TGOS C Programming 3 02-28-2005 10:49 AM
Function delcared inline but not defined inline Nish C Programming 4 10-08-2004 03:31 PM



Advertisments