Creating C macro with ## and __LINE__ (token concatenation with positioning macro)

Viewed 68300

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?

3 Answers

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
Related