Search

4.6 — Typedefs and type aliases

Typedefs allow the programmer to create an alias for a data type, and use the aliased name instead of the actual type name. To declare a typedef, simply use the typedef keyword, followed by the type to alias, followed by the alias name:

By convention, typedef names are declared using a “_t” suffix. This helps indicate that they are types, not variables, and also helps prevent naming collisions with similarly named variables.

A typedef does not define a new type. Rather, it is simply an alias (another name) for an existing type. A typedef can be used interchangeably anywhere a regular type can be used.

Even though the following does not make sense conceptually, it is valid C++:

Typedefs are useful in a number of different situations.

Using typedefs for legibility

One use for typedefs is to help with documentation and legibility. Data type names such as char, int, long, double, and bool are good for describing what type a function returns, but more often we want to know what purpose a return value serves.

For example, consider the following function:

We can see that the return value is an integer, but what does the integer mean? A letter grade? The number of questions missed? The student’s ID number? An error code? Who knows! Int does not tell us anything.

However, using a return type of testScore_t makes it obvious that the function is returning a type that represents a test score.

Using typedefs for easier code maintenance

Typedefs also allow you to change the underlying type of an object without having to change lots of code. For example, if you were using a short to hold a student’s ID number, but then later decided you needed a long instead, you’d have to comb through lots of code and replace short with long. It would probably be difficult to figure out which shorts were being used to hold ID numbers and which were being used for other purposes.

However, with a typedef, all you have to do is change typedef short studentID_t to typedef long studentID_t. However, precaution is necessary when changing the type of a typedef to a type in a different type family (e.g. an integer to a floating point value, or vice versa)! The new type may have comparison or integer/floating point division issues that the old type did not.

Platform independent coding

One big advantage of typedefs is that they can be used to hide platform specific details. On some platforms, an integer is 2 bytes, and on others, it is 4. Thus, using int to store more than 2 bytes of information can be potentially dangerous when writing platform independent code.

Because char, short, int, and long give no indication of their size, it is fairly common for cross-platform programs to use typedefs to define aliases that include the type’s size in bits. For example, int8_t would be an 8-bit signed integer, int16_t a 16-bit signed integer, and int32_t a 32-bit signed integer. Using typedef names in this manner helps prevent mistakes and makes it more clear about what kind of assumptions have been made about the size of the variable.

In order to make sure each typedef type resolves to a type of the right size, typedefs of this kind are typically used in conjunction with the preprocessor:

On machines where integers are only 2 bytes, INT_2_BYTES can be #defined, and the program will be compiled with the top set of typedefs. On machines where integers are 4 bytes, leaving INT_2_BYTES undefined will cause the bottom set of typedefs to be used. In this way, int8_t will resolve to a 1 byte integer, int16_t will resolve to a 2 bytes integer, and int32_t will resolve to a 4 byte integer using the combination of char, short, int, and long that is appropriate for the machine the program is being compiled on.

In C++11, this is actually how the fixed width integers (like int8_t) were defined! As a side-effect of the fact that int8_t is actually a typedef of char, the following code acts somewhat unexpectedly:

This program prints:

a

not 97, because std::cout prints char as an ASCII character, not a number.

Using typedefs to make complex types simple

Although we have only dealt with simple data types so far, in advanced C++, you could see a variable and function declared like this:

Typing std::vector<std::pair<std::string, int> > everywhere you need to use that type can get cumbersome. It’s much easier to use a typedef:

Much better! Now we only have to type “pairlist_t” instead of std::vector<std::pair<std::string, int> >.

Don’t worry if you don’t know what std::vector, std::pair, or all these crazy angle brackets are yet. The only thing you really need to understand here is that typedefs allow you to take complex types and given them a simple name, which makes those types easier to work with and understand.

Type aliases in C++11

Typedefs have a few issues. First, it’s easy to forget whether the type name or type definition come first. Which is correct?

I can never remember.

Second, the syntax for typedefs gets ugly with more complex types (as we’ll explore further in the section on function pointers).

To help address these issues, in C++11, a new, improved syntax for typedefs has been introduced that mimics the way variables are declared. This syntax is called a type alias. A type alias introduces a name that can be used as a synonym for a type.

Given the following typedef:

In C++11, this can be declared as:

The two are functionally equivalent.

Note that although the C++11 syntax uses the “using” keyword, this is an overloaded meaning, and does not have anything to do with the using statements related to namespacing.

This new syntax is cleaner for more advanced typedefing cases, and should be preferred if you compiler is C++11 capable.

Rule: Favor type aliases over typedefs if your compiler is C++11 compatible.

Quiz time

1) Given the following function prototype:

1a) Convert the int return value to a typedef named error_t using the typedef keyword. Include both the typedef statement and the updated function prototype.

Show Solution

1b) Convert the int return value to a typedef named error_t using the using keyword (C++11). Include both the typedef statement and the updated function prototype.

Show Solution

4.7 -- Structs
Index
4.5a -- Enum classes

21 comments to 4.6 — Typedefs and type aliases

  • P,JBoy

    Is there any reason typedefs should be used rather than #defines?

    • typedefs are generally safer and harder to inadvertently screw up than #defines.

      Here’s an example of where using a typedef is better than using a #define:

      In the second example, you were probably expecting pW to be of type int*, but it’s of type int instead!

      • george

        I would think this:

        #define int* intptrdef;
        intptrdef pZ, pW;

        translates to this:
        int* pZ, pW

        in which case both should be pointers.

        • Alex

          You would think so, but “int* pZ, pW” declares an integer pointer named pZ and an integer named pW.

          • Darren

            Think of the asterisk that defines a pointer-to-type as being part of the identifier and not the type specifier. Which is why some prefer the spacing

            to

  • CSESTUDENT

    Ok I wrote a program like this to calculate distance in km and I used DistanceCovered as alias for the type double:

    It is returning me something like this when I run it in the g++ compiler:
    /usr/lib/gcc/i486-linux-gnu/4.3.3/../../../../lib/crt1.o: In function `_start’:
    /build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:115: undefined reference to `main’

    I’m sure something is wrong with my code but I can’tfind what!

    • Zak

      Well what is obviously missing is the int main() section. I took the code and copied it and added the int main() section and it worked perfectly.

  • I understand the typedef stuff ok but the :

    This just lost me good.
    Where is the if else coming from. If “what” or else “why”. Is the preprocessor comparing something? Or is this an example of code that could be written?
    Your tutorial is great, it is filling in a lot of holes I had in my attempt to teach myself c++. My problem is that my brain has very little RAM. I guess I chewed on too many lead bars when I was kid. It was ok back then to chew on lead bars, 60 years ago you didn’t need brains like today. I was going to do a site on learning c++ but I can’t beat this site so I will put links on my sites leading to yours. This is pro stuff you got, real education taught by an educator.
    thanks

    • Alex

      We cover most of this in lesson 1.10 -- a first look at the preprocessor and header guards.

      Basically, the preprocessor is checking to see whether INT_2_BYTES has been #defined somewhere. This could be defined in your program somewhere, or passed to the compiler directly (all compilers have a way for the user to pass in defines directly). If it has been defined, the top set of code is compiled. If not, the bottom set of code is compiled. This is called “conditional compilation”, if you want to do more reading on it.

      • Matt

        I am a little confused too.

        If we use this conditional code because we don’t know what type of system the program will end up running on(whether an int will be 2 bytes or 4 bytes), then at what point in coding would we be able to make the decision to #define INT_2_BYTES?

        Or are you saying that we in fact would not know beforehand which set of typdefs to compile, and that we would have to compile the program twice to make two different versions for two different systems?

        • Alex

          Most likely you’d do this when you’re distributing your source code. That way, someone on a machine that has 2 byte integers could #define INT_2_BYTES and compile your source code, producing an executable that runs correctly on their machine.

  • An alternative to using typedefs would of course be using comments, for example:

    I prefer using comments for at least three reasons:

    1. You only need one line of code (if you, like me, want a linebreak after each semicolon, that is).

    2. There’s one keyword (typedef) less to learn how to use, and you can learn to use something else instead.

    3. The risk of making a mistake is greatly reduced. In other words, if you make a typo inside a comment it doesn’t matter while it usually does if you make one outside a comment.

  • DanielN91

    Hi!

    I want to thank you for these tutorials. They are extremely helpful, concise and clear. I’ve been helped by them in many ways and every time I read them it seems like I’m learning something simple. I’m grateful for people like you, who want to share what they know and know how to do it.

    Keep up the good work! 🙂

    Learning from you,
    Daniel.

  • Todd

    Typo.

    "A typedef does not define (a) new type."

  • anvekar

    In this where exactly is INT_2_BYTES defined? It can’t be in our program as we are unaware of the size of integer in any specific system.

    • Alex

      You’d have to define it in your program, somewhere above this point (or define it as a compiler flag as part of your project).

      How to determine whether integers are 2 bytes or not as part of the preprocessing phase is more complicated (but there are ways to do so, otherwise libraries like pstdint.h couldn’t exist.

  • carr002

    In modern c++ this would be usually be written as

    Use of using rather than typedef is now preferred.

  • John J

    std::vector<std::pair<std::string, int>>

    I’ve just finished section 4.6 and am loving the tutorials, but…did I miss something?  Or am I not supposed to know exactly what this means yet?  I think the only thing I skipped was bitwise operators to this point.  I know the std stands for the standard namespace.  At first glance, vector and pair both look like functions and std::string, int are the parameters of the function pair.

    If this is covered soon hereafter, I guess just point me to the lesson or I’ll come across it sooner than later.  Otherwise, if it were covered before this lesson, please refresh my memory because I’m not seeing exactly what I think I’m supposed to at the moment.

    Edit: After reading further, it appears now to me that vector and pair are just types in the std namespace, but I guess I’m still confused about the brackets and what they mean in terms of connecting them all. Any help would be appreciated, thanks.

    • Alex

      No, you didn’t miss anything. The key takeaway here is just that typedes allow you to assign a simple alias to something that can potentially be much more complicated. You don’t need to know anything about std::vector, std::pair, or all those crazy angle brackets yet. We’ll cover those in due time.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter