简体   繁体   中英

C style struct declaration

I have a quick question about C style struct's. I was digging through some sample code and found a struct declared in the following way:

typedef struct _STRUCTNAME
{
   // struct contents
} STRUCTNAME;

Please note the lack of an underscore on the second time STRUCTNAME shows up. My understanding was that this would declare a single _STRUCTNAME called STRUCTNAME and no more objects of this struct could be instantiated.

However, this does not seem to be the case. A struct of this type was never actually instantiated in the code except in one place: in a global array of such objects that was used in random places:

const struct STRUCTNAME ARRAYNAME[] = 
{
   // various STRUCTNAMEs declared here
};

Note the lack of an underscore again (which I thought was the name of the instantiated object?)

Is my understanding completely off?

Could someone explain?

typedef struct _STRUCTNAME
{
   // struct contents
} STRUCTNAME;

This piece of code does two things:

  1. Defines a structure called struct _STRUCTNAME and
  2. Creates a typedef of that structure called STRUCTNAME .

The reason for this is that in proper C code, the way you would otherwise declare a struct (like the above) would be the following:

struct _STRUCTNAME structInstance;

However, with the typedef in place, you can simply use the following:

STRUCTNAME structInstance;

The same holds true for enum declarations.

STRUCTNAME is the typedef name.

_STRUCTNAME is the 'tag' for the struct, which is in a different namespace.

Prior to the ANSI standardization, the structure tag namespace wasn't separate in many compilers, so to prevent a name collision with the typedef name it had to be different. However, since standardization there is no need for the tag name to be different.

You see this idiom often used in Windows code, no doubt because it was that way in many examples from the SDK. Raymond Chen wrote a blog post about it a while back:

Also, I'm sure there will be some comments about how the _STRUCTNAME identifier is reserved for the implementation, so it's not a good idea to use that form in any case.

Michael Burr said:

Also, I'm sure there will be some comments about how the _STRUCTNAME identifier is reserved for the implementation, so it's not a good idea to use that form in any case.

OK, I'm game (but I wanted some formatting so you get an answer instead):

A language standard is a contract between compiler-writer and compiler-user, where each promises to do and not do certain things.

Most identifiers beginning with _ are reserved for the implementation - including all identifiers beginning with _ followed by an uppercase letter. This means that the compiler-writer is allowed to use them for any purpose whatsoever, because the compiler-user has promised not to use them.

Compiler-users who break their promise get weird results.

Conversely, all identifiers that the [applicable] standard does not reserve for the implementation are guaranteed to be available to the compiler-user because the compiler-writer has promised not to use them.

Compiler-writers who break their promise get refund demands, when valid code gets weird results.

My preference is to put a trailing _ on tag names, include guards, etc., ensuring that I stay out of the implementation's space; thus:

typedef struct STRUCTNAME_
{
   // struct contents
} STRUCTNAME;

(Some purists frown on typedef s as merely syntactic sugar, but C needs a bit of sugar here and there, otherwise it can seem pretty bland.)

I believe your confusion is why the identifier list at the end of the struct definition is not instantiating instances. The reason is because you have included the typedef keyword.

Consider the syantax for typedef :

typedef type-definition identifier;

What you have done is provided your struct as the type-definition. Instead of creating instances, you are defining a type. Constrast this to instantiating instances where the struct is simply defining the type inline:

struct STRUCTNAME
{
   // struct contents
} myStruct, *ptr, alsoMyStruct;

When you don't include the typedef keyword, the identifier just specifies instances as usual.

const struct STRUCTNAME ARRAYNAME[] = 
{
   // various STRUCTNAMEs declared here
};

the above code is not going to compile for incomplete type for the array. I think thers typo it should be

const struct _STRUCTNAME ARRAYNAME[] = ...

Alternatively you can use typedefs without specifying struct keyword

const STRUCTNAME ARRAYNAME[] =

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM