Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #21867 > unrolled thread

interpret this code?

Started byGeorge <gbeccles@verizon.net>
First post2012-06-05 08:26 -0400
Last post2012-06-05 22:50 -0400
Articles 9 — 6 participants

Back to article view | Back to comp.lang.c


Contents

  interpret this code? George <gbeccles@verizon.net> - 2012-06-05 08:26 -0400
    Re: interpret this code? James Kuyper <jameskuyper@verizon.net> - 2012-06-05 09:19 -0400
      Re: interpret this code? Nick Bowler <nbowler@draconx.ca> - 2012-06-05 15:55 +0000
        Re: interpret this code? James Kuyper <jameskuyper@verizon.net> - 2012-06-05 12:05 -0400
    Re: interpret this code? "BartC" <bc@freeuk.com> - 2012-06-05 14:42 +0100
      Re: interpret this code? Noob <root@127.0.0.1> - 2012-06-05 16:19 +0200
    Re: interpret this code? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-06-05 14:43 +0100
    Re: interpret this code? Noob <root@127.0.0.1> - 2012-06-05 16:22 +0200
    Re: interpret this code? George <gbeccles@verizon.net> - 2012-06-05 22:50 -0400

#21867 — interpret this code?

FromGeorge <gbeccles@verizon.net>
Date2012-06-05 08:26 -0400
Subjectinterpret this code?
Message-ID<30urs79vrgihohjaoca4g3bj1kfbcqa5jk@4ax.com>
I'm working on an old (comment-free) program, and finding some of the
code is above my pay grade.  I'd appreciate insight into what's going on
with the segment below.

-----------------
  #define SCRN_LIST \
     SCRN(Null) \
     SCRN(RYG) \
     SCRN(Fr00) \
     SCRN(LastN) \
     SCRN(DateTime) \

  #define INIT_LIST \
     INIT(Default) \
     INIT(LastN) \
     INIT(EvtLog) \
     INIT(EvtLogDetail) \

  typedef void (*VOID_FNC)(void);
   
  #define SCRN(symm) (const VOID_FNC)symm##ScrnFnc,
  #define INIT(symm) (const VOID_FNC)symm##InitFnc,
    const VOID_FNC ScrnFnc[] = {
       SCRN_LIST
       INIT_LIST
    };
  #undef  SCRN
  #undef  INIT

    // typical fnc
     
  void
  NullScrnFnc(void) { ... }
-----------------

I think the final result wants to be ...
  const void (*ScrnFnc[])() = { 
    NullScrnFnc, 
    RYGScrnFnc, 
    ...
    DefaultInitFnc,
    LastNInitFnc,
    ...
  };
  
Even assuming that's correct, I don't see how it gets there.  I see that
SCRN_LIST/INIT_LIST will cause ea of their listed arguments (Null, RYG,
etc) to instantiate the 'SCRN'/'INIT' macros in the ScrnFnc[]
declaration,  But, ISTM, this would create something like (eg) ...
  void (*NullFnc)()


Bonus points: I don't know how to 'read' the VOID_FNC typedef.  I think
that's a standard construct (ptr to void fnc?), but the logic of it
eludes me.

Thanks,
George

[toc] | [next] | [standalone]


#21868

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-06-05 09:19 -0400
Message-ID<jql115$4v4$1@dont-email.me>
In reply to#21867
On 06/05/2012 08:26 AM, George wrote:
> I'm working on an old (comment-free) program, and finding some of the
> code is above my pay grade.  I'd appreciate insight into what's going on
> with the segment below.
> 
> -----------------
>   #define SCRN_LIST \
>      SCRN(Null) \
>      SCRN(RYG) \
>      SCRN(Fr00) \
>      SCRN(LastN) \
>      SCRN(DateTime) \
> 
>   #define INIT_LIST \
>      INIT(Default) \
>      INIT(LastN) \
>      INIT(EvtLog) \
>      INIT(EvtLogDetail) \
> 
>   typedef void (*VOID_FNC)(void);
>    
>   #define SCRN(symm) (const VOID_FNC)symm##ScrnFnc,
>   #define INIT(symm) (const VOID_FNC)symm##InitFnc,
>     const VOID_FNC ScrnFnc[] = {
>        SCRN_LIST
>        INIT_LIST
>     };
>   #undef  SCRN
>   #undef  INIT
> 
>     // typical fnc
>      
>   void
>   NullScrnFnc(void) { ... }
> -----------------
> 
> I think the final result wants to be ...
>   const void (*ScrnFnc[])() = { 
>     NullScrnFnc, 
>     RYGScrnFnc, 
>     ...
>     DefaultInitFnc,
>     LastNInitFnc,
>     ...
>   };
>   
> Even assuming that's correct, I don't see how it gets there.  I see that
> SCRN_LIST/INIT_LIST will cause ea of their listed arguments (Null, RYG,
> etc) to instantiate the 'SCRN'/'INIT' macros in the ScrnFnc[]
> declaration,  But, ISTM, this would create something like (eg) ...
>   void (*NullFnc)()

The expansion is actually

	(const VOID_FUNC)NullScrnFnc

The equivalent without use of typedefs would be:

	(void(*)(void) const)NullScrnFnc

In other words, it is an expression declaring that NullScrnFnc is an
object of type (void(*)(void) const). A typedef is not simply a macro,
which is why the const needs to be moved to the end of the cast. In an
expression like "const int i", the keyword const modifies 'i'; the same
is true in "const VOID_FUNC NullScrnFnc". However, if we were to write
"const void(*)(void) NullScrnFnc", then the 'const' would (with
undefined behavior - 6.7.3p9) modify the return type from the function.
You need to move the 'const' to the end of the type specification for it
to have the same meaning as it has in 'const VOID_FUNC'.

> Bonus points: I don't know how to 'read' the VOID_FNC typedef.  I think
> that's a standard construct (ptr to void fnc?), but the logic of it
> eludes me.

The way to read a typedef is to first interpret it as an ordinary
declaration, without the typedef. In this case, that would give us:

	void (*VOID_FNC)(void);

What this would mean is that (*VOID_FUNC)() would be an expression of
type void. The second pair of parentheses mean that (*VOID_FUNC) is a
function. The second 'void' means that the function does not take any
arguments. The '*' would indicate that VOID_FUNC is a pointer. Put that
all together, and it would mean that VOID_FUNC is a pointer to a
function taking no arguments and returning nothing.

The effect of prefixing the declaration with "typedef" is that instead
of VOID_FNC being the identifier for an object of that type, it's an
alias for the type of such an object.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#21876

FromNick Bowler <nbowler@draconx.ca>
Date2012-06-05 15:55 +0000
Message-ID<jqla67$2rm$1@dont-email.me>
In reply to#21868
On 2012-06-05 09:19:33 -0400, James Kuyper wrote:
> On 06/05/2012 08:26 AM, George wrote:
[...]
>>   typedef void (*VOID_FNC)(void);
[...]
> The expansion is actually
> 
> 	(const VOID_FUNC)NullScrnFnc
> 
> The equivalent without use of typedefs would be:
> 
> 	(void(*)(void) const)NullScrnFnc

This is a syntax error.  I think you meant:

  (void(* const)(void))NullScrnFnc

> In other words, it is an expression declaring that NullScrnFnc is an
> object of type (void(*)(void) const).

It doesn't declare anything, and that again is not a valid type name.

> A typedef is not simply a macro, which is why the const needs to be moved to
> the end of the cast. In an expression like "const int i", the keyword const
> modifies 'i'; the same is true in "const VOID_FUNC NullScrnFnc". However, if
> we were to write "const void(*)(void) NullScrnFnc",

Another syntax error... I think you meant:

  const void(*NullScrnFnc)(void)

> then the 'const' would (with undefined behavior - 6.7.3p9) modify the return
> type from the function.

Assuming the above correction is what you meant, C11 6.7.3p9 does not
apply since (as you have stated) the qualifier applies to the return
type (which is not a function type), not the function type itself.  The
only way to actually qualify a function type or an array type (and thus
make 6.7.3p9 apply) is by using a typedef, as in:

  typedef void func_type(void);
  const func_type explode; /* qualified function type, UB by C11 6.7.3p9 */

Of course, const-qualifying the return type of a function make little
sense (especially if it's void!), but it is nevertheless valid.

[toc] | [prev] | [next] | [standalone]


#21877

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-06-05 12:05 -0400
Message-ID<4FCE2E56.304@verizon.net>
In reply to#21876
On 06/05/2012 11:55 AM, Nick Bowler wrote:
> On 2012-06-05 09:19:33 -0400, James Kuyper wrote:
>> On 06/05/2012 08:26 AM, George wrote:
> [...]
>>>   typedef void (*VOID_FNC)(void);
> [...]
>> The expansion is actually
>>
>> 	(const VOID_FUNC)NullScrnFnc
>>
>> The equivalent without use of typedefs would be:
>>
>> 	(void(*)(void) const)NullScrnFnc
> 
> This is a syntax error.  I think you meant:
> 
>   (void(* const)(void))NullScrnFnc

You're right.

>> In other words, it is an expression declaring that NullScrnFnc is an
>> object of type (void(*)(void) const).
> 
> It doesn't declare anything, and that again is not a valid type name.

I got confused at one point, thinking this was occurring inside a
parameter list for a function. When I corrected that misunderstanding, I
failed to correct all of the writing I'd done based upon that
misunderstanding.

[toc] | [prev] | [next] | [standalone]


#21871

From"BartC" <bc@freeuk.com>
Date2012-06-05 14:42 +0100
Message-ID<jql2c2$efi$1@dont-email.me>
In reply to#21867
"George" <gbeccles@verizon.net> wrote in message
news:30urs79vrgihohjaoca4g3bj1kfbcqa5jk@4ax.com...
> I'm working on an old (comment-free) program, and finding some of the
> code is above my pay grade.

Or possibly just below it. Code shouldn't be unnecessarily obscure. Not if 
someone else needs to make head or tail of it.

> I think the final result wants to be ...
>  const void (*ScrnFnc[])() = {
>    NullScrnFnc,
>    RYGScrnFnc,
>    ...
>    DefaultInitFnc,
>    LastNInitFnc,
>    ...
>  };
>
> Even assuming that's correct, I don't see how it gets there.  I see that
> SCRN_LIST/INIT_LIST will cause ea of their listed arguments (Null, RYG,
> etc) to instantiate the 'SCRN'/'INIT' macros in the ScrnFnc[]
> declaration,  But, ISTM, this would create something like (eg) ...
>  void (*NullFnc)()

I passed the code through a compiler option to generate the output of the
preprocessor (-E on gcc). The output, with editing to improve the layout,
is:

    const VOID_FNC ScrnFnc[] = {
     (const VOID_FNC)NullScrnFnc,
     (const VOID_FNC)RYGScrnFnc,
     (const VOID_FNC)Fr00ScrnFnc,
     (const VOID_FNC)LastNScrnFnc,
     (const VOID_FNC)DateTimeScrnFnc,
     (const VOID_FNC)DefaultInitFnc,
     (const VOID_FNC)LastNInitFnc,
     (const VOID_FNC)EvtLogInitFnc,
     (const VOID_FNC)EvtLogDetailInitFnc,
    };

Now why couldn't it have looked like that in the first place?

-- 
Bartc
 

[toc] | [prev] | [next] | [standalone]


#21873

FromNoob <root@127.0.0.1>
Date2012-06-05 16:19 +0200
Message-ID<jql4h5$s8j$1@dont-email.me>
In reply to#21871
BartC wrote:

> I passed the code through a compiler option to generate the output of the
> preprocessor (-E on gcc). The output, with editing to improve the layout,

http://linux.die.net/man/1/indent

[toc] | [prev] | [next] | [standalone]


#21872

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-06-05 14:43 +0100
Message-ID<0.ffa2f10b467662d9567f.20120605144335BST.87mx4hc1rs.fsf@bsb.me.uk>
In reply to#21867
George <gbeccles@verizon.net> writes:

> I'm working on an old (comment-free) program, and finding some of the
> code is above my pay grade.  I'd appreciate insight into what's going on
> with the segment below.
>
> -----------------
>   #define SCRN_LIST \
>      SCRN(Null) \
>      SCRN(RYG) \
>      SCRN(Fr00) \
>      SCRN(LastN) \
>      SCRN(DateTime) \
>
>   #define INIT_LIST \
>      INIT(Default) \
>      INIT(LastN) \
>      INIT(EvtLog) \
>      INIT(EvtLogDetail) \
>
>   typedef void (*VOID_FNC)(void);
>    
>   #define SCRN(symm) (const VOID_FNC)symm##ScrnFnc,
>   #define INIT(symm) (const VOID_FNC)symm##InitFnc,
>     const VOID_FNC ScrnFnc[] = {
>        SCRN_LIST
>        INIT_LIST
>     };
>   #undef  SCRN
>   #undef  INIT
>
>     // typical fnc
>      
>   void
>   NullScrnFnc(void) { ... }
> -----------------
>
> I think the final result wants to be ...
>   const void (*ScrnFnc[])() = { 

The type is actually

   void (*const ScrnFnc[])(void)

Your () is not quite the same as (void), and the const refers to the
whole pointer type -- i.e. the elements of the array are read-only.  In
your version, what is const is the returned type of the functions
pointer to by the array elements and one never writes such things.
Writing

  const int f(void);

is pointless.  Of course one often sees

  const char *f(void);

or

  char const *f(void);

but here what is const is the pointed-to type: f is a function returning
a pointer to const char (or char const).  A function returning a const pointer
type is never written:

  char *const f(void);

Once the programmer has defined the "pointer to function type" called
VOID_FNC, making *that* const applies to the pointers in the array.

Adding the the fact that ScrnFnc is an array makes the type harder to
write but all C types are easy to readif you know the trick.  This is
such a common issue that I've put a page up about this:

  http://bsb.me.uk/c-types

>     NullScrnFnc, 
>     RYGScrnFnc, 
>     ...
>     DefaultInitFnc,
>     LastNInitFnc,
>     ...
>   };

The result is actually

const VOID_FNC ScrnFnc[] = {
     (const VOID_FNC)NullScrnFnc,
     (const VOID_FNC)RYGScrnFnc,
     ...
     (const VOID_FNC)DefaultInitFnc,
     (const VOID_FNC)LastNInitFnc,
     ...
  };

because VOID_FNC is a typedef and so not "expanded", but I know what you
meant.
   
> Even assuming that's correct, I don't see how it gets there.  I see that
> SCRN_LIST/INIT_LIST will cause ea of their listed arguments (Null, RYG,
> etc) to instantiate the 'SCRN'/'INIT' macros in the ScrnFnc[]
> declaration,  But, ISTM, this would create something like (eg) ...
>   void (*NullFnc)()

Hmmm... not sure why you say that so I can't readily help.  The typedef
is not expanded, of course.  Maybe that's part of the confusion?

> Bonus points: I don't know how to 'read' the VOID_FNC typedef.  I think
> that's a standard construct (ptr to void fnc?), but the logic of it
> eludes me.

Does my linked page help with that?

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#21874

FromNoob <root@127.0.0.1>
Date2012-06-05 16:22 +0200
Message-ID<jql4m8$s8j$2@dont-email.me>
In reply to#21867
George wrote:

> Bonus points: I don't know how to 'read' the VOID_FNC typedef.  I think
> that's a standard construct (ptr to void fnc?), but the logic of it
> eludes me.

http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html

[toc] | [prev] | [next] | [standalone]


#21885

FromGeorge <gbeccles@verizon.net>
Date2012-06-05 22:50 -0400
Message-ID<49dts7psft3ph0irj7l52gae2hcs05jci0@4ax.com>
In reply to#21867
Thanks to all who replied.  My question is answered, and then some.
Another step on the road to enlightenment, though it will take me a bit
to digest.

George

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web