0

I've known about using preprocessor instructions to shorten type names similar to this:

#define LL long long

However, I've seen someone use a different approach:

using LL = long long;

Are there any differences between these two, apart from the syntax? Which one would be more recommended in most cases?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
BiT
  • 27
  • 3
  • 5
    `#define` is the C way, but regardless, **don't do this**. Please. `LL` and other "cute" abbreviations are an absolute scourge. If you need to be specific, [use a descriptive type](https://en.cppreference.com/w/cpp/types/integer) identifier. – tadman Feb 06 '23 at 22:12
  • 3
    Yes, please use a standard type like `int64_t`. I believe these are defined with `typedef` on most systems. The `using` or `typedef` syntax prevents the user from adding something like `signed` or `unsigned` to the type. – David Grayson Feb 06 '23 at 22:13
  • They are more different than they are alike. Everything about how they are implemented is completely different. – user229044 Feb 06 '23 at 22:13
  • 1
    Most importantly the `#define` is _not_ a type alias at all. It works on a completely different level than types. It is token (text) replacement without any regard for what the tokens mean. – user17732522 Feb 06 '23 at 22:14
  • 4
    Even in C using `#define` is the Wrong Way™. You should `typedef long long LL` (or whatever better name you have for the thing you are representing than “LL”). – Dúthomhas Feb 06 '23 at 22:15
  • As a tangential note, there's is already an [integer suffix `LL`](https://en.cppreference.com/w/cpp/language/integer_literal#The_type_of_the_literal) in the language, don't introduce ambiguity. – Bob__ Feb 06 '23 at 22:36
  • Just change `#define LL long long` to `#define DANGER_THIS_IS_A_MACRO_LL long long` and it'll be fine. – Eljay Feb 06 '23 at 23:22
  • 1
    `void f(int LL);` is legal with one approach and not with the other. – Pete Becker Feb 07 '23 at 17:28

2 Answers2

6

using (or typedef before C++11) is the preferred approach. It creates a proper type alias that is actually treated by the compiler as a type and as nothing else.

One very important reason NOT to use #define in this manner is that it is handled globally by the preprocessor before the compiler is invoked. It doesn't understand or respect C++ syntax. It is just arbitrary text replacement, and it will unconditionally replace all occurrences of the defined symbol with the specified text, regardless of where the symbol appears in the code.

So, for example, if you have a function, variable, class type, basically any identifier named LL, the #define you have shown will replace it with long long, corrupting the code's syntax, eg:

#define LL long long

void Func1(LL value); // OK: compiler sees "void Func1(long long value);"
void Func2(char LL); // ERROR: compiler sees "void Func2(char long long);"
void LL(arguments...); // ERROR: compiler sees "void long long(arguments...);"

class LL // ERROR: compiler sees "class long long"
{
    LL value; // OK: compiler sees "long long value;"
    void Method1(LL value); // OK: compiler sees "void Method1(long long value);"
    void Method2(char LL); // ERROR: compiler sees "void Method2(char long long);"
    void LL(arguments...); // ERROR: compiler sees "void long long(arguments...);"
};

Whereas a using (or typedef) type alias will not corrupt the code's syntax like that:

using LL = long long; // or: typedef long long LL;

void Func1(LL value); // OK: compiler sees "void Func1(long long value);"
void Func2(char LL); // OK: compiler sees "void Func2(char LL);"
void LL(arguments...); // OK: compiler sees "void LL(arguments...);"

class LL // OK: compiler sees "class LL"
{
    LL value; // OK: compiler sees "long long value;"
    void Method1(LL value); // OK: compiler sees "void Method1(long long value);"
    void Method2(char LL); // OK: compiler sees "void Method2(char LL);"
    void LL(arguments...); // OK: compiler sees "void LL(arguments...);"
};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

Better than both would be to use typedef long long LL;, as that's the preferred way to do type aliasing in C and C++. Better still for short types like this it's better to just write the type out to make it easier to read.

The runner up is using, as it's functionally equivalent, however as it's a C++ exclusive feature it's less common than typedef (a lot of C++ programmers started out as C programmers). Still though, it's essentially just a matter of preference.

Regardless, the accepted practice seems to be to minimize use of the preprocessor wherever possible. Using #define macros is essentially just telling the compiler "HEY! Before you start actually compiling, make sure to go through and run a find and replace on this text". This can lead to unexpected behaviors, for example if instead of a source (.c/.cc/.cpp) file you put the define directive in a header file, the find and replace operation will work on every file included after that point, including libraries and dependencies that are compiled as part of your build process. This can be nearly impossible to track down and fix if it creates a problem. If for any reason you have to use a preprocessor directive, it's best to make sure the token is long/specific enough that you're unlikely to run into any sort of collision unintentionally, to use it in a source file rather than a header file, or to end the place in which its used with #undef.

  • *"[`typedef`]'s the preferred way to do type aliasing in C and C++"* -- no, it's only preferred in C. (In C++, `typedef` is preferred to a macro, but it at best ties with `using` for preferred use.) And since the question is tagged for C++, not C, the preference for C is irrelevant. – JaMiT Feb 06 '23 at 23:52
  • 1
    *"however as it's a C++ exclusive feature"* -- What's wrong with using a C++ exclusive feature in C++ code? C++ features exist so that they can be used. (Again, the question is tagged for C++, not C.) – JaMiT Feb 06 '23 at 23:57
  • @JaMiT You're right, typedef is more common but it's not as though there's anything wrong with using. I tried to edit my answer a bit to better reflect that. – pizzamonkey Feb 10 '23 at 01:24