Typedef and enum with same name? - c

In the library FreeImagePlus, in FreeImage.h, there is a funny #define which seems to create a typedef and an enum with the same name:
#define FI_ENUM(x) typedef int x; enum x
This is expanded by the preprocessor to code like:
typedef int FREE_IMAGE_FILTER;
enum FREE_IMAGE_FILTER {
FILTER_BOX = 0,
FILTER_BICUBIC = 1,
[...]
What does this do? Is it even legal to have a typedef and an enum with the same name?
And isn't an enum compatible to int anyway? Why does FreeImage do this?

Names of structures, unions and enumerations lives in their own namespace. That's why you can declare a struct/union/enum variable with the same name as the actual struct/union/enum.
And it's not the name of the complete enum (e.g. for enum X I mean the X) that has to be compatible with an integer, it's the names inside the enumeration.

Quoting C99 N1256 draft 6.2.1 "Scopes of identifiers":
An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter.
which means that in:
typedef int id;
id is an identifier.
And from 6.2.3 "Name spaces of identifiers":
BEGIN QUOTE
If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:
label names (disambiguated by the syntax of the label declaration and use);
the tags of structures, unions, and enumerations (disambiguated by following any of the keywords struct, union, or enum);
the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);
all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).
END QUOTE
So in:
typedef int id;
enum id {ID0};
the first id is an ordinary identifier
the second is a tag identifier
an both can coexist pacifically.
On the other hand, we could not do something like:
typedef int id;
int id;
because both would be ordinary identifiers.

Related

Is typedef allowed before definition

Minimum code:
// foo.h
typedef struct foo_s foo_t;
struct foo_s {
foo_t* next;
};
iwyu insists I forward declare struct foo_s before I typedef it to foo_t.
Output:
$ iwyu -c foo.h
foo.h should add these lines:
struct foo_s;
foo.h should remove these lines:
The full include-list for foo.h:
struct foo_s;
---
This is true across different versions of iwyu, including newer versions with -Xiwyu --no_fwd_decls added.
Is this a mistake in iwyu or does the C standard want me to define the type before the typedef?
does the C standard want me to define the type before the typedef?
It does not. The standard verbiage is as follows
6.7.2.3 Tags
7 A declaration of the form
struct-or-union identifier ;
specifies a structure or union type and declares the identifier as a
tag of that type.
8 If a type specifier of the form
struct-or-union identifier
occurs other than as part of one of the above forms, and no other
declaration of the identifier as a tag is visible, then it declares an
incomplete structure or union type, and declares the identifier as the
tag of that type.
So your original pair of declarations has well-defined behavior. The declaration for the structure is implicitly added into the translation unit at the point you define the type alias, and then completed afterward. The fact that the tool does not allow it may be due to a bug, a limitation of the tool, or perhaps an attempt to enforce a particular coding style.
There is one point in favor of the style that the tool may try to enforce, and it has to do with the C notion of scope. Specifically, function parameter list scope. As an example, see this Q&A and refer to this short example
void bar(struct foo);
struct foo {
char c;
};
void bar(struct foo f) {}
It so happens that the first declaration of bar is declared with a type that is unique to its parameter list. The initial declaration of struct foo is not the same type as the one used in the later function definition. As such, the code
will not compile by a conforming C compiler. Declaring the structure on its own line ahead of the first function declaration fixes this problem.
This C11 Draft Standard makes it quite clear that you can 'forward declare' a typedef struct..., by way of an example that is very similar to your code:
6.7.2.3 Tags ... 11 The following alternative formulation uses the typedef mechanism:
typedef struct tnode TNODE;
struct tnode {
int count;
TNODE *left, *right;
};
TNODE s, *sp;
It is a bug. It seems the typedef for a structure is considered the same way as a typedef for an enumeration.
For enumerations you may not use an incomplete type in a typedef definition
From the C Standard (6.7.2.3 Tags)
3 A type specifier of the form
enum identifier
without an enumerator list shall only appear after the type it
specifies is complete.
So for example such a typedef
typedef enum E AnotherE;
enum E { N };
is invalid while this typedef
enum E { N };
typedef enum E AnotherE;
is valid.
For structures you may use an incomplete type in a typedef definition.
8 If a type specifier of the form
struct-or-union identifier
occurs other than as part of one of the above forms, and no other
declaration of the identifier as a tag is visible, then it declares an
incomplete structure or union type, and declares the identifier as the
tag of that type.

Some questions about struct namespace in C

I'm trying to understand this answer - typedef struct vs struct definitions [duplicate]:
(Line 3): ["] In the first line you are defining the identifier S within the struct name space (not in the C++ sense). [."]
It seems like for struct X {...};, the {...} is like an adjective for X, and X {...} is thrown into something called struct-namespace, how many struct-namespace are there in a program? Is there only one specified by struct?
It seems like in C/C++ struct and class are almost the same? So in C++ struct and class are both in class-namespace?
From the C99 standard draft
6.2.3
6.2.3 Name spaces of identifiers
If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate namespaces
for various categories of identifiers, as follows:
—label names
(disambiguated by the syntax of the label declaration and use);
—the
tags
of structures, unions, and enumerations (disambiguated by following any
of the keywords
struct
,
union
,or
enum
);
—the
members
of structures or unions; each structure or union has a separate name
space for its members (disambiguated by the type of the expression used to access the
member via the
.
or
->
operator);
—all other identifiers, called
ordinary identifiers
(declared in ordinary declarators or as
enumeration constants).
In other words, if you have struct S, then S is in the struct namespace, whereas if you have int S as well, then it's in the namespace of ordinary identifiers.
This is not the case for C++
1 (for C): there is one namespace for all structure tags. You can have as many different tags as you want, even if the same name is used in other namespaces.
Each structure on its own is its own namespace (there are "infinite" struct namespaces).
// You can have
struct foo { int var; }
struct bar { double var; }
struct baz { int var; }
struct qux { int var; }
// with no conflict between all the `var`

Why doesn't the compiler give a conflicting error?

In following code, I have declared a structure member variable as a same name of structure name.
struct st
{
int st;
};
int main()
{
struct st t;
t.st = 7;
return 0;
}
I wonder, it's working fine on GCC compiler and doesn't give a conflict error.
So,
How does the compiler know structure name and variable name?
What mechanism compiler internally use?
Yes, it's valid. The struct tag and the struct members are in different namespace.
C11, 6.2.3 Name spaces of identifiers:
If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:
label names (disambiguated by the syntax of the label declaration and use);
the tags of structures, unions, and enumerations (disambiguated by following any32) of the keywords struct, union, or enum);
the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);
all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).
The name of the structure type is struct st. Not just st, so there's no conflict at all.

In C, can struct members use the same name as a type?

For example, is the following valid C code?
typedef struct {
/* ... */
} foo;
typedef struct {
foo foo; /* Is it ok that 'foo' == 'foo'? */
} bar;
Yes that is valid C (although it is not readable and should be avoided).
Types identifiers and struct members identifiers live in different name spaces.
See C99, 6.2.3p1 Name spaces of identifiers:
[...] there are separate name spaces for various categories of identifiers, as follows:
— label names (disambiguated by the syntax of the label declaration and use);
— the tags of structures, unions, and enumerations [...]
— the members of structures or unions; each structure or union has a separate name
space for its members [...]
— all other identifiers, called ordinary identifiers [...]

type namespace in C

I've read in SO about different namespaces in C where the type are defined, e.g. there is a namespace for Structs and Unions and a namespace for typedefs.
Is namespace the exact name for this? How many namespaces exist in C?
see 6.2.3
from http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
6.2.3 Name spaces of identifiers
If more than one declaration of a particular identifier is visible at
any point in a translation unit, the syntactic context disambiguates uses
that refer to different entities.
Thus, there are separate name spaces for various categories of identifiers,
as follows:
— label names (disambiguated by the syntax of the label declaration and use);
— the tags of structures, unions, and enumerations (disambiguated by
following any32) of the keywords struct, union, or enum);
— the members of structures or unions; each structure or union has a
separate name space for its members (disambiguated by the type of the
expression used to access themember via the . or -> operator);
— all other identifiers, called ordinary identifiers (declared in ordinary
declarators or as enumeration constants).
I am not sure if "namespace" is the right word here, but I think I know what you mean.
You can do
union name1 { int i; char c; };
struct name2 { int i; char c; };
enum name3 { A, B, C };
typedef int name4;
int name5;
Here name1, name2 and name3 are in distinct "namespaces" (I'll keep that word for now), as they don't collide with each other.
This implies that using them requires to prefix their use with the respective keyword:
struct name1 var; // valid
name1 var; // invalid
On the other hand, name4 and name5 live in the global "namespace" and collide. So after having typedef int name4;, you cannot define a variable with that name name4.
BTW: The labels as well define their own namespace.

Resources