127

I want to create a C macro that creates a function with a name based on the line number. I thought I could do something like (the real function would have statements within the braces):

#define UNIQUE static void Unique_##__LINE__(void) {}

Which I hoped would expand to something like:

static void Unique_23(void) {}

That doesn't work. With token concatenation, the positioning macros are treated literally, ending up expanding to:

static void Unique___LINE__(void) {}

Is this possible to do?

Dr. Gut
  • 2,053
  • 7
  • 26
DD.
  • 1,273
  • 2
  • 9
  • 4
  • 4
    possible duplicate of [How to concatenate twice with the C preprocessor and expand a macro as in "arg ## \_ ## MACRO"?](http://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg) The same goes for any macro besides `__LINE__` (although that is a common use case. – Ciro Santilli OurBigBook.com Jun 21 '15 at 09:54
  • I think you can get this to work with [indirect macro expansion](http://en.wikipedia.org/wiki/C_preprocessor#Indirectly_quoting_macro_arguments). – Ben Stiglitz Oct 20 '09 at 20:28

3 Answers3

208

The problem is that when you have a macro replacement, the preprocessor will only expand the macros recursively if neither the stringizing operator # nor the token-pasting operator ## are applied to it. So, you have to use some extra layers of indirection, you can use the token-pasting operator with a recursively expanded argument:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

Then, __LINE__ gets expanded to the line number during the expansion of UNIQUE (since it's not involved with either # or ##), and then the token pasting happens during the expansion of TOKENPASTE.

It should also be noted that there is also the __COUNTER__ macro, which expands to a new integer each time it is evaluated, in case you need to have multiple instantiations of the UNIQUE macro on the same line. Note: __COUNTER__ is supported by MS Visual Studio, GCC (since V4.3), and Clang, but is not standard C.

Warty
  • 7,237
  • 1
  • 31
  • 49
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 3
    I'm afraid that doesn't work with GNU cpp. TOKENPASTE uses __LINE__ as a literal. TOKENPASTE(Unique_, __LINE__) expands to Unique___LINE__ – DD. Oct 20 '09 at 20:58
  • 4
    @DD: D'oh, fixed now. It needs 2 layers of indirection, not 1. – Adam Rosenfield Oct 20 '09 at 21:04
  • The `__COUNTER__` macro didn't work for me in gcc; although the `__LINE__` one did work as advertised. – Tyler Sep 30 '11 at 00:27
  • 2
    Bit of extra information for anyone trying __COUNTER__, according to http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx it is a macro specific to Microsoft. – Elva Mar 04 '12 at 14:08
  • @Yourdoom: GCC also supports `__COUNTER__` (since V4.3). I edited the answer. – sleske Jun 05 '14 at 18:55
  • 5
    Any explanation of why you need 2 level of indirection? I've tried it with just one, absent of # and ##, and that does not expand it on VS2017. Apparently the same is true for GCC. But if you add a 2nd level of indirection, then it does expand. Magic? – Gabe Halsmer Nov 16 '17 at 14:37
  • @AdamRosenfield can you look at similar question https://stackoverflow.com/questions/65798613/stringizing-with-function-not-working – gaurav bharadwaj Jan 19 '21 at 19:59
  • Can you add some demo usages to this answer please? Also, how do we see the unique names that are generated? – Gabriel Staples Apr 17 '22 at 03:39
  • I found a really good example demo, with output showing the generated variable name. See here: [Create an identifier at compile time that has the line number as part of it](https://stackoverflow.com/a/35922379/4561887) – Gabriel Staples Apr 17 '22 at 03:56
  • I posted a [generic answer with another demo here.](https://stackoverflow.com/a/71899854/4561887) – Gabriel Staples Apr 17 '22 at 06:41
2

How to auto-generate unique variable names with the line number in them by using macros

This is a generic answer, not addressing the narrow specifics of the OP's question, since there are already adequate answers for that.

I learned this primarily from @Jarod42 here, but also from @Adam.Rosenfield here.

#define CONCAT_(prefix, suffix) prefix##suffix
/// Concatenate `prefix, suffix` into `prefixsuffix`
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
/// Make a unique variable name containing the line number at the end of the
/// name. Ex: `uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0;` would
/// produce `uint64_t counter_7 = 0` if the call is on line 7!
#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)

Example program:

macro_make_unique_variable_name_with_line_number.c:

#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h>  // For `uint8_t`, `int8_t`, etc.
#include <stdio.h>   // For `printf()`

#define CONCAT_(prefix, suffix) prefix##suffix
/// Concatenate `prefix, suffix` into `prefixsuffix`
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
/// Make a unique variable name containing the line number at the end of the
/// name. Ex: `uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0;` would
/// produce `uint64_t counter_7 = 0` if the call is on line 7!
#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)


// int main(int argc, char *argv[])  // alternative prototype
int main()
{
    printf("Autogenerate unique variable names containing the line number "
           "in them.\n\n");

    uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_54 = 0;
    uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_55 = 0;
    uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_56 = 0;

    // Uncomment this to suppress the errors.
    // (void)counter_54;
    // (void)counter_55;
    // (void)counter_56;

    return 0;
}

SAMPLE OUTPUT:

Notice that the intentionally-produced build errors reveal the autogenerated variable names as counter_56, counter_55, and counter_54, as shown here!:

macro_make_unique_variable_name_with_line_number.c:56:40: error: unused variable ‘counter_56’ [-Werror=unused-variable]
macro_make_unique_variable_name_with_line_number.c:55:40: error: unused variable ‘counter_55’ [-Werror=unused-variable]
macro_make_unique_variable_name_with_line_number.c:54:40: error: unused variable ‘counter_54’ [-Werror=unused-variable]

Full output:

eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 macro_make_unique_variable_name_with_line_number.c -o bin/a -lm && bin/a
macro_make_unique_variable_name_with_line_number.c: In function ‘main’:
macro_make_unique_variable_name_with_line_number.c:56:40: error: unused variable ‘counter_56’ [-Werror=unused-variable]
   56 |     uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_56 = 0;
      |                                        ^~~~~~~
macro_make_unique_variable_name_with_line_number.c:39:33: note: in definition of macro ‘CONCAT_’
   39 | #define CONCAT_(prefix, suffix) prefix##suffix
      |                                 ^~~~~~
macro_make_unique_variable_name_with_line_number.c:45:43: note: in expansion of macro ‘CONCAT’
   45 | #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
      |                                           ^~~~~~
macro_make_unique_variable_name_with_line_number.c:56:14: note: in expansion of macro ‘MAKE_UNIQUE_VARIABLE_NAME’
   56 |     uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_56 = 0;
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~
macro_make_unique_variable_name_with_line_number.c:55:40: error: unused variable ‘counter_55’ [-Werror=unused-variable]
   55 |     uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_55 = 0;
      |                                        ^~~~~~~
macro_make_unique_variable_name_with_line_number.c:39:33: note: in definition of macro ‘CONCAT_’
   39 | #define CONCAT_(prefix, suffix) prefix##suffix
      |                                 ^~~~~~
macro_make_unique_variable_name_with_line_number.c:45:43: note: in expansion of macro ‘CONCAT’
   45 | #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
      |                                           ^~~~~~
macro_make_unique_variable_name_with_line_number.c:55:14: note: in expansion of macro ‘MAKE_UNIQUE_VARIABLE_NAME’
   55 |     uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_55 = 0;
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~
macro_make_unique_variable_name_with_line_number.c:54:40: error: unused variable ‘counter_54’ [-Werror=unused-variable]
   54 |     uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_54 = 0;
      |                                        ^~~~~~~
macro_make_unique_variable_name_with_line_number.c:39:33: note: in definition of macro ‘CONCAT_’
   39 | #define CONCAT_(prefix, suffix) prefix##suffix
      |                                 ^~~~~~
macro_make_unique_variable_name_with_line_number.c:45:43: note: in expansion of macro ‘CONCAT’
   45 | #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
      |                                           ^~~~~~
macro_make_unique_variable_name_with_line_number.c:54:14: note: in expansion of macro ‘MAKE_UNIQUE_VARIABLE_NAME’
   54 |     uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_54 = 0;
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
-3

GCC doesn't require "wrapping" (or realizing) unless the result needs to be "stringified". Gcc has features but ALL can be done with plain C version 1 (and some argue Berkeley 4.3 C is so much faster it's worth learning how to use).

**Clang (llvm) DOES NOT DO WHITE SPACE CORRECTLY for macro expansion - it adds whitespace (which certainly destroy's the result as being a C Identifier for further pre-processing) **, clang simply doesn't do # or * macro expansion as a C Preprocessor is expected to for decades. The prime example is compiling X11, macro "Concat3" is broken, it's result is now MISNAMED C Identifier, which of course fails to build. and i'm beginning to thing build fails are their profession.

I think the answer here is "new C that breaks standards is bad C", these hacks always choose to (clobber namespaces) they change defaults for no reason but do not really "improve C" (excepting to their own say so: which i say is contraption made to explain why they get away with all the breakage no one yet has made them responsible for).


It's not a problem that the earlier C pre-processors did not support UNIq_()__ because they supported #pragma which allows "compiler brand hackery in code to be flagged as hackery" and also function just as well WITHOUT effecting standards: just as changing defaults is useless wonton breakage, and just as changing what a function does while using the same name (namespace clobbering) is ... malware in my opinion