39

What are the rules? OTOH the simple case seems to imply the new type is the last thing on a line. Like here Uchar is the new type:

typedef unsigned char Uchar;

But a function pointer is completely different. Here the new type is pFunc:

typedef int (*pFunc)(int);

I can't think of any other examples offhand but I have come across some very confusing usages.

So are there rules or are people just supposed to know from experience that this is how it is done because they have seen it done this way before?

ALSO: What is the scope of a typedef?

Mailerdaimon
  • 6,003
  • 3
  • 35
  • 46
ValenceElectron
  • 2,678
  • 6
  • 26
  • 27
  • also may want to research `typedef typename ` construct – Anycorn Mar 11 '10 at 18:50
  • 2
    "So are there rules" - nah, we just make up syntax as we go along. The compilers then read our minds to see what we meant. –  Mar 11 '10 at 18:54
  • @aaa: `typedef typename` construct? `typename` is used in templates to disambiguate types. It would be part of a type; it's not a special form of `typedef`. – CB Bailey Mar 11 '10 at 18:55
  • This is like saying you want to research the `typedef class` construct. – Johannes Schaub - litb Mar 11 '10 at 19:06
  • C++11's alias declarations (typedefs with `using`) can be more readable, especially with function pointers. They're also necessary for templated typedefs. So, you may want to look at those, too. A good guide would be https://msdn.microsoft.com/en-CA/library/dn467695.aspx . – Justin Time - Reinstate Monica Feb 02 '16 at 22:26

3 Answers3

74

Basically a typedef has exactly the same syntax as an object declaration except that it is prefixed with typedef. Doing that changes the meaning of the declaration so that the new identifier declares an alias for the type that the object that would have been declared, had it been a normal declaration, would have had.

A typedef is scoped exactly as the object declaration would have been, so it can be file scoped or local to a block or (in C++) to a namespace or class.

e.g.

Declares an int:

int a;

Declares a type that is an alias for int:

typedef int a_type;

Declares a pointer to a char:

char *p;

Declares an alias for a char *:

typedef char *pChar;

Declares a function pointer:

int (*pFn)(int);

Declares an alias for the type that is 'pointer to a function taking int and returning int':

typedef int (*pFunc)(int);
pro-gramer
  • 166
  • 1
  • 3
  • 14
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
11

For syntactic convenience, typedef is treated as a storage class specifier, like extern, static, or register. Semantically of course it's quite different, but when typedef was added to the language, it was simpler to use an existing piece of the grammar to define its syntax.

Adding static to an object declaration doesn't change the meaning of the declaration except that it changes the object's storage class to "static" (if it wasn't already):

{
    int foo; /* automatic storage duration */
    static int bar; /* static storage duration */
}

Replacing static with typedef changes the meaning of the declaration, so that the name being defined is not an object name but a type name (actually just an alias for an existing type):

    typedef int baz; /* "baz" is an alias for "int" */

The same syntax applies to more complex declarations:

int (*a)[42];         /* a is a pointer to an array of 42 ints */
static int (*b)[42];  /* Same as a, but with static storage duration */
typedef int (*c)[42]  /* c is an alias for the type int(*)[42], or 
                         "pointer to array of 42 ints" */

Once you realize that typedef was arbitrarily shoved into the same slot in the grammar occupied by extern, static, and register, understanding typedef declarations is no harder (and no easier!) than understanding object declarations. (The cdecl program and web site are useful for unpacking complex declarations.)

You can also have a typedef for a function type:

void func(void);              /* declare func as a function */
typedef void func_type(void); /* declare func_type as a name
                                 for a function type */

You can't use a typedefed function type to declare or define a function, but you can use it to declare a function pointer:

func_type *ptr = func;

As for scope (meaning the region of program text over which a declared identifier is visible), an identifier defined by a typedef declaration has the same scope as any other declared identifier. If it's declared at file scope, outside any function, it's visible from the point of declaration to the end of the file. If it's declared inside a function, it's visible from the point at which it's declared to the end of the nearest enclosing block. And like any declaration, it can be hidden by another declaration with the same name in an inner scope.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • This answer should have more upvotes, since it explains the scope issue (came here just for that) – J3STER Feb 23 '17 at 10:54
  • @J3STER: Thank you, but the accepted answer also addresses scope. – Keith Thompson Feb 23 '17 at 17:59
  • Oh you are right, I totally missed it, (Minor dislexia) – J3STER Feb 23 '17 at 18:39
  • So, ODR violations **can** occur when two `typedef`s with the same name (designating different things) live in different translation units? In short, I should put file scope `typedef`s in unnamed namespaces, same as I do for local (declared and defined in a source file) classes. – Lorah Attkins Jan 07 '20 at 10:04
0

Just because no one else mentioned it: It is always localised to any object build. So if you're compiling different cpp files with the same using/typedef name then they won't effect each other.

Elliott
  • 2,603
  • 2
  • 18
  • 35