|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
I am playing with some code that has been automatically generated
from ASN.1 data specification found in RFC 3280. One of the structures generated reads as follows: typedef struct TBSCertList { Version_t *version /* OPTIONAL */; AlgorithmIdentifier_t signature; Name_t issuer; Time_t thisUpdate; struct Time *nextUpdate /* OPTIONAL */; struct revokedCertificates { A_SEQUENCE_OF(struct Member { CertificateSerialNumber_t userCertificate; Time_t revocationDate; struct Extensions *crlEntryExtensions / * OPTIONAL */; /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; } ) list; /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; } *revokedCertificates; struct Extensions *crlExtensions /* OPTIONAL */; /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; } TBSCertList_t; /* Implementation */ extern asn_TYPE_descriptor_t asn_DEF_TBSCertList; } where A_SEQUENCE_OF() is defined as #define A_SEQUENCE_OF(type) \ struct { \ type **array; \ int count; /* Meaningful size */ \ int size; /* Allocated size */ \ void (*free)(type *); \ } The preprocessor expands this as typedef struct TBSCertList { Version_t *version; AlgorithmIdentifier_t signature; Name_t issuer; Time_t thisUpdate; struct Time *nextUpdate; struct revokedCertificates { struct { struct Member { CertificateSerialNumber_t userCertificate; Time_t revocationDate; struct Extensions *crlEntryExtensions; asn_struct_ctx_t _asn_ctx; } **array; int count; int size; void (*free) (struct Member { CertificateSerialNumber_t userCertificate; Time_t revocationDate; struct Extensions * crlEntryExtensions; asn_struct_ctx_t _asn_ctx; } *); } list; asn_struct_ctx_t _asn_ctx; } *revokedCertificates; struct Extensions *crlExtensions; asn_struct_ctx_t _asn_ctx; } TBSCertList_t; This compiles all right, but the GCC compiler generates the following warning: TBSCertList.h:47: warning: structure defined inside parms TBSCertList.h:47: warning: `struct Member' declared inside parameter list TBSCertList.h:47: warning: its scope is only this definition or declaration, which is probably not what you want Line 47 is the line that reads } ) list; in the code above, before the preprocessing. Now I want to believe that this code is generated the way it is generated for some good reason. What I do not understand is what the compiler is complaining about. Anybody care to explain? What is it about struct Member that the compiler reckons that that's not what we want? |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
"James H. Newman" <NewJa...@exicite.com> wrote:
<snip> > This compiles all right, but the GCC compiler > generates the following warning: > > TBSCertList.h:47: warning: structure defined inside parms > TBSCertList.h:47: warning: `struct Member' declared inside parameter list > TBSCertList.h:47: warning: its scope is only this definition or > declaration, which is probably not what you want This is Question 11.5 in the FAQ... http://c-faq.com/ansi/structinproto.html -- Peter |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On Wed, 06 Feb 2008 00:16:59 GMT, "James H. Newman"
<NewJames@exicite.com> wrote in comp.lang.c: > I am playing with some code that has been automatically generated > from ASN.1 data specification found in RFC 3280. One of the structures > generated reads as follows: > > typedef struct TBSCertList { > Version_t *version /* OPTIONAL */; > AlgorithmIdentifier_t signature; > Name_t issuer; > Time_t thisUpdate; > struct Time *nextUpdate /* OPTIONAL */; > struct revokedCertificates { > A_SEQUENCE_OF(struct Member { > CertificateSerialNumber_t userCertificate; > Time_t revocationDate; > struct Extensions *crlEntryExtensions / > * OPTIONAL */; > > /* Context for parsing across buffer boundaries */ > asn_struct_ctx_t _asn_ctx; > } ) list; > > /* Context for parsing across buffer boundaries */ > asn_struct_ctx_t _asn_ctx; > } *revokedCertificates; > struct Extensions *crlExtensions /* OPTIONAL */; > > /* Context for parsing across buffer boundaries */ > asn_struct_ctx_t _asn_ctx; > } TBSCertList_t; > > /* Implementation */ > extern asn_TYPE_descriptor_t asn_DEF_TBSCertList; > } > > where A_SEQUENCE_OF() is defined as > > #define A_SEQUENCE_OF(type) \ > struct { \ > type **array; \ > int count; /* Meaningful size */ \ > int size; /* Allocated size */ \ > void (*free)(type *); \ > } > > The preprocessor expands this as > > typedef struct TBSCertList { > Version_t *version; > AlgorithmIdentifier_t signature; > Name_t issuer; > Time_t thisUpdate; > struct Time *nextUpdate; > struct revokedCertificates { > struct { > struct Member { > CertificateSerialNumber_t userCertificate; > Time_t revocationDate; > struct Extensions *crlEntryExtensions; > asn_struct_ctx_t _asn_ctx; > } **array; > int count; > int size; > void (*free) (struct Member { > CertificateSerialNumber_t userCertificate; > Time_t revocationDate; > struct Extensions * crlEntryExtensions; > asn_struct_ctx_t _asn_ctx; > } *); > } list; > > asn_struct_ctx_t _asn_ctx; > } *revokedCertificates; > struct Extensions *crlExtensions; > > asn_struct_ctx_t _asn_ctx; > } TBSCertList_t; > > This compiles all right, but the GCC compiler generates the > following warning: > > TBSCertList.h:47: warning: structure defined inside parms > TBSCertList.h:47: warning: `struct Member' declared inside parameter list > TBSCertList.h:47: warning: its scope is only this definition or > declaration, which is probably not what you want > > Line 47 is the line that reads > > } ) list; > > in the code above, before the preprocessing. > > Now I want to believe that this code is generated the way it is > generated for some good reason. What I do not understand is what the > compiler is complaining about. Anybody care to explain? What is it about > struct Member that the compiler reckons that that's not what we want? C has something called "prototype scope". It applies to both names and types that are defined inside the argument list of a function prototype. These definitions go out of scope at the end of the prototype. You can see this most easily in names: int func(int argument); int func(int different); int func(int x) { return x + 1; } The compiler will not complain that because the first prototype names the argument "argument" but the second prototype for the same function names it "different". Nor that the function definition gives it yet a third name. The same thing applies to types such as structs, unions, and enums defined in a prototype scope. Consider this: int func( struct two_ints { int x; int y; } ); struct two_ints file_scope_two_ints my_two_ints; Compiling a file containing these two lines will is required to generate a diagnostic on the struct object definition, because there is no definition of "struct two_ints" in scope at that point. In fact, if we insert a third line between the two, to get: int func( struct two_ints { int x; int y; } ); struct two_ints { double a; double b; double c; }; struct two_ints file_scope_two_ints my_two_ints; Then the object "my_two_ints" will actually contain three doubles, and a later call in the same translation unit: int result = func( my_two_ints ); ....will net a diagnostic about calling "func" with an incompatible argument type. That is why struct, union, and enum definitions are usually defined outside of their area of use, in a header, for example, or before their first use if they are used in multiple places in a file. C states that struct types are compatible if they neither has a tag name or they both have the same tag names, and if the is a one-to-one relationship between the order, types, and names of their members. That is guaranteed when there is one and only one definition of the struct type, and it is in scope everywhere the type is used. Presumably, somewhere else in another source or header file, is a prototype and/or definition of a function whose address will eventually be stored in the "free" member of a struct list. It will need to have a definition of the structure type it accepts, which probably comes from physically different text than the source of this macro. If somebody changes the definition of the struct type in one place or the other, but not all places, then suddenly you have problems, undefined behavior, "mysterious" defects, etc. It would be much better to put the definition of struct Member in a header, and include that header everywhere it is used. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
Peter Nilsson wrote:
> "James H. Newman" <NewJa...@exicite.com> wrote: > <snip> >> Â Â Â Â This compiles all right, but the GCC compiler >> generates the following warning: >> >> TBSCertList.h:47: warning: structure defined inside parms >> TBSCertList.h:47: warning: `struct Member' declared inside parameter list >> TBSCertList.h:47: warning: its scope is only this definition or >> declaration, which is probably not what you want > > This is Question 11.5 in the FAQ... > > http://c-faq.com/ansi/structinproto.html > That is about function parameters, not macro parameters. -- Army1987 (Replace "NOSPAM" with "email") |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
"James H. Newman" wrote:
> > I am playing with some code that has been automatically generated > from ASN.1 data specification found in RFC 3280. One of the structures > generated reads as follows: [...snip...] > The preprocessor expands this as > > typedef struct TBSCertList { [...] > struct revokedCertificates { > struct { > struct Member { > CertificateSerialNumber_t userCertificate; > Time_t revocationDate; > struct Extensions *crlEntryExtensions; > asn_struct_ctx_t _asn_ctx; > } **array; > int count; > int size; > void (*free) (struct Member { > CertificateSerialNumber_t userCertificate; > Time_t revocationDate; > struct Extensions * crlEntryExtensions; > asn_struct_ctx_t _asn_ctx; > } *); > } list; [...] > } TBSCertList_t; > > This compiles all right, but the GCC compiler generates the > following warning: > > TBSCertList.h:47: warning: structure defined inside parms > TBSCertList.h:47: warning: `struct Member' declared inside parameter list > TBSCertList.h:47: warning: its scope is only this definition or > declaration, which is probably not what you want > > Line 47 is the line that reads > > } ) list; > > in the code above, before the preprocessing. [...] Look at this part in the middle of the macro expansion: > void (*free) (struct Member { > CertificateSerialNumber_t userCertificate; > Time_t revocationDate; > struct Extensions * crlEntryExtensions; > asn_struct_ctx_t _asn_ctx; > } *); You are declaring a member of the struct called "free", which is a function pointer, and you are prototyping that function. Within that prototype, you are declaring a struct called "Member". This "struct Member" is not the same "struct Member" that you define a few lines earlier, because it is an actual definition, not just a reference. (Yes, it is the same name and an identical layout, but that doesn't matter as far as the warning is concerned.) Consider this valid, though probably useless, snippet: struct foo { int a; int b; }; extern void func1( struct foo *foopt ); extern void func2( struct foo { float a; float b; } *foopt ); Just as the third warning states: its scope is only this definition or declaration, which is probably not what you want Change it so that the expansion is: void (*free)(struct Member *); -- +-------------------------+--------------------+-----------------------+ | Kenneth J. Brody | www.hvcomputer.com | #include | | kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> | +-------------------------+--------------------+-----------------------+ Don't e-mail me at: <mailto:ThisIsASpamTrap@gmail.com> |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
Army1987 <army1987@NOSPAM.it> writes:
> Peter Nilsson wrote: > >> "James H. Newman" <NewJa...@exicite.com> wrote: >> <snip> >>> Â Â Â Â This compiles all right, but the GCC compiler >>> generates the following warning: >>> >>> TBSCertList.h:47: warning: structure defined inside parms >>> TBSCertList.h:47: warning: `struct Member' declared inside parameter list >>> TBSCertList.h:47: warning: its scope is only this definition or >>> declaration, which is probably not what you want >> >> This is Question 11.5 in the FAQ... >> >> http://c-faq.com/ansi/structinproto.html >> > That is about function parameters, not macro parameters. The warning messages are about function parameters, not macro parameters. The function parameter declaration happens to be within a macro expansion, but that's irrelevant. (By the time the compiler gets to the phase where it produces the warning, all macros have been processed and are no longer visible.) -- Keith Thompson (The_Other_Keith) <kst-u@mib.org> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
Keith Thompson wrote:
> Army1987 <army1987@NOSPAM.it> writes: >> That is about function parameters, not macro parameters. > > The warning messages are about function parameters, not macro > parameters. The function parameter declaration happens to be within a > macro expansion, but that's irrelevant. (By the time the compiler > gets to the phase where it produces the warning, all macros have been > processed and are no longer visible.) Oh, I had missed the declaration of free. -- Army1987 (Replace "NOSPAM" with "email") |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
"Jack Klein" <jackklein@spamcop.net> wrote in message
news 4biq3hie4uqngudg0h8prmbvbpg81bp6t@4ax.com...> [snip: excellent explanation of what the warning means] > > If somebody changes the definition of the struct type in one place or > the other, but not all places, then suddenly you have problems, > undefined behavior, "mysterious" defects, etc. > > It would be much better to put the definition of struct Member in a > header, and include that header everywhere it is used. While I'd agree with all of the above if the code were maintained by a human, it should be pointed out that the OP stated this code is automatically generated. As long as one trusts that tool to keep the definitions consistent (and in this example, it obviously does so), the code is safe and the warning can be ignored or disabled. If the tool breaks, you'll likely have far, far bigger problems than a simple compiler warning. I'd, however, look into whether it's possible to modify the tool to generate the code a bit more like a human would, i.e. in a way that doesn't trigger this warning. S -- Stephen Sprunk "God does not play dice." --Albert Einstein CCIE #3723 "God is an inveterate gambler, and He throws the K5SSS dice at every possible opportunity." --Stephen Hawking |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
Stephen Sprunk wrote:
> While I'd agree with all of the above if the code were maintained by a > human, it should be pointed out that the OP stated this code is > automatically generated. As long as one trusts that tool to keep the > definitions consistent (and in this example, it obviously does so), the > code is safe and the warning can be ignored or disabled. If the tool > breaks, you'll likely have far, far bigger problems than a simple > compiler warning. > > I'd, however, look into whether it's possible to modify the tool to > generate the code a bit more like a human would, i.e. in a way that > doesn't trigger this warning. No, such a prototype is broken because it is useless - it is impossible to define or call a function declared in such a way that it defines a new type in a conforming way. The compiler is entitled to (and many do) reject such attempts. Neil. |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
[Structure declarations with function prototype scope]
On Fri, 08 Feb 2008 22:17:00 +0900, Neil Booth wrote: > No, such a prototype is broken because it is useless - Almost, but not completely. > it is impossible > to define or call a function declared in such a way that it defines a > new type in a conforming way. The compiler is entitled to (and many do) > reject such attempts. Exactly, and that gives it some actual use. You're probably aware that function pointers can be converted to different function pointers, and that no generic function pointer type exists. For that reason, you can use something like void(*)(void) as a generic function pointer type, and cast it whenever you want to use it. That's great, except you might accidentally call the function -- there's no reason for the compiler to reject fp(); if fp has that type, or even warn about it. If you instead use void(*)(struct incomplete) as your generic function pointer type, the compiler will not let you call the function without a cast, because there's no way to pass an argument of type struct incomplete. |
|
![]() |
| Outils de la discussion | |
|
|