Repeated Typedefs - Invalid in C But Valid in C++

Repeated typedefs - invalid in C but valid in C++?

Why does this compile in C++?

Because the C++ Standard explicitly says so.

Reference:

C++03 Standard 7.1.3 typedef specifier

§7.1.3.2:

In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.

[Example:

typedef struct s { /* ... */ } s;

typedef int I;

typedef int I;

typedef I I;

—end example]

Why does this fail to compile in C?

typedef names have no linkage and C99 standard disallows identifiers with no linkage specification to have more than one declaration with the same scope and in the same name space.

Reference:

C99 Standard: §6.2.2 Linkages of identifiers

§6.2.2/6 states:

The following identifiers have no linkage: an identifier declared to be anything other than
an object or a function; an identifier declared to be a function parameter;
a block scope
identifier for an object declared without the storage-class specifierextern.

Further §6.7/3 states:

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except for tags as specified in 6.7.2.3.

Right location to define structs and typedefs

This depends on how much information you want to share with the outside world.

Assuming, that struct is to be shared between multiple translation units, the most straighforward way is to put struct type declaration into a header file. It is called as complete struct declaration:

struct f3{
double x;
double y;
double z;
};

The second way is to hide the members by the incomplete struct declaration, sometimes refferred to as forward declaration or an opaque pointer. This way you can hide the details of how members are placed inside.

header.h

struct f3;

source.c

#include "header.h"

struct f3{
double x;
double y;
double z;
};

This form requires, that any function from the public interface must only contain parameters, that are pointers to that struct as well as they can return such struct only by a pointer. In other words, you cannot refer to the struct directly, only by a pointer. For example:

double area(struct f3* point);
struct f3* makePoint(int x, int y, int z);

Right location to define structs and typedefs

This depends on how much information you want to share with the outside world.

Assuming, that struct is to be shared between multiple translation units, the most straighforward way is to put struct type declaration into a header file. It is called as complete struct declaration:

struct f3{
double x;
double y;
double z;
};

The second way is to hide the members by the incomplete struct declaration, sometimes refferred to as forward declaration or an opaque pointer. This way you can hide the details of how members are placed inside.

header.h

struct f3;

source.c

#include "header.h"

struct f3{
double x;
double y;
double z;
};

This form requires, that any function from the public interface must only contain parameters, that are pointers to that struct as well as they can return such struct only by a pointer. In other words, you cannot refer to the struct directly, only by a pointer. For example:

double area(struct f3* point);
struct f3* makePoint(int x, int y, int z);

Why can't we typedef an (unnamed) structure twice at file scope, but we can typedef int twice without error?

The thing is that when you do:

typedef struct
{

} Somestruct;

It creates an anonymous struct - you can expect some hidden implementation-defined guaranteed-unique placeholder identifier to be used - for which you specify the typedef. So, when you do it twice you get a conflict in having the same typedef-ed name asked to refer to two distinct structures. With int, you're simply repeating the original. If you give the struct an actual name then that lets you repeat the typedef:

typedef struct Somestruct
{

} Somestruct;

Why can't redefine type names in class in C++?

This is not unique to types. [basic.class.scope]/2:

A name N used in a class S shall refer to the same declaration in its
context and when re-evaluated in the completed scope of S. No
diagnostic is required for a violation of this rule.

The reason is that name lookup in class scope is a little special. Consider:

using Foo = int;

struct X {
Foo a; // ::Foo, i.e., int
void meow() {
Foo b = a; // X::Foo; error: no conversion from int to char*
}
using Foo = char*;
};

Name lookup in member function bodies considers all class members, whether declared before or after the member function (otherwise, a member function defined in a class definition wouldn't be able to use a data member declared later in the class). The result is that you get two Foos with different meanings, even though they both lexically precede the class member Foo's declaration. This can easily lead to extremely confusing and brittle code, and so the standard bans it.

Typedef in header file that's included multiple times

By using include guards.

#ifndef ARRAY_H_
#define ARRAY_H_

typedef struct {
...
} array;

#endif

Does C compiler distinguish type defined in user's code and library code?

Repeating a declaration is perfectly valid in C, so if you uncomment both lines as you describe you will not see any error, contrary to what you say.

Having two different declarations for a name would be an error.

Repeating a definition is an error as well, but a typedef is not a definition (despite the def), it is a declaration.

using C struct that is declared later

Replace this line:

// i would place a sort of struct prototype here

with these lines:

struct TheType;
typedef struct TheType TheType;

Since you need the type TheType to be defined before type Container is defined, you have to use forward declaration of type TheType - and to do so you also need forward declaration of struct TheType.

Then you will not define typedef TheType like this:

typedef struct {......} TheType;

but you will define struct TheType:

struct {......};


Related Topics



Leave a reply



Submit