Why can't I fill in the typedef with the name of the array type?

Standard states C (Β§6.2.5, p22):

An unknown array size type is incomplete. It is completed, for an identifier of this type, indicating the size in a later version of the declaration (with internal or external communication).

And it works great with respect to variable declarations:

int a[]; int a[2]; //OK 

But when we add a typedef in front of these declarations, the compiler complains (I also changed the name):

 typedef int t[]; typedef int t[2]; //redefinition with different type 

He does not complain, however, when we complete the typedef for an incomplete structure:

 typedef struct t t1; typedef struct t { int m; } t1; //OK 

A possible use case for an incomplete typedef array might be something like this:

 int main(int n, char **pp) { typedef int t1[][200]; typedef struct t { t1 *m; int m1; } t0; typedef int t1[sizeof (t0)][200]; } 

In the above example, I would like to declare a pointer to an array inside the structure with the number of elements equal to the size of the structure. Yes, I could use a structure instead of an array, but why should I use a potentially available option?

+8
c arrays language-lawyer
source share
2 answers

typedef int t[2]; not allowed due to limitation 6.7 / 3:

If the identifier is not bound, there should be no more than one identifier declaration (in a pointer or type specifier) ​​with the same scope and in the same namespace, except that:

  • the typedef name can be redefined to indicate the same type as it is currently provided, provided that the type is not a changed type;

However, int[] and int[2] are not the same type, therefore this "exception" does not apply, therefore the code violates the restriction.


Regarding your first quote: although 6.2.5 / 22 says that an incomplete type can be completed, it does not follow from this that any attempt to complete is automatically legal. An attempt to complete must also comply with all other language rules, in which case it does not comply with 6.7 / 3.

Example int a[]; int a[2]; int a[]; int a[2]; in order (under 6.7 / 3), because a has a connection; and in typedef struct t t1; , struct t remains the same type before and after its completion.

+4
source share

From 6.2.5p1 we can see the definition of complete and incomplete terms:

At different points within the translation unit, the type of object may be incomplete (not having enough information to determine the size of objects of this type) or complete (having enough information).

Thus, when we talk about an incomplete type, we really say that the size of objects of this type is indefinite. We cannot talk about "incomplete types" without declaring an object of this type.

In the first example, the size of a is determined because you completed the definition of the object using the second declaration.

In your second example, declarations for the object are not created. After declaring a declaration, for example. tx = { 1, 2 }; , it becomes clear that the type is not incomplete.

In the third example, you are not actually populating the type alias; you complete the definition of struct . You could write:

 typedef struct t t1; struct t { int m; }; 

We can see further support for struct tag redefinition and the exception of VLA redefinition in 6.7p3 :

If the identifier is not bound, there should be no more than one identifier declaration (in a pointer or type specifier) ​​with the same scope and in the same namespace, except that:

  • the typedef name can be redefined to indicate the same type as it is currently, provided that the type is not a changed type; Tags
  • can be updated as specified in 6.7.2.3.
0
source share

All Articles