使用 ## 和 __LINE__ 创建 C 宏(与定位宏的标记串联)

问题描述 投票:0回答:2

我想创建一个 C 宏来创建一个基于名称的函数 在行号上。 我想我可以做类似的事情(真正的函数在大括号内有语句):

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

我希望能扩展到类似:

static void Unique_23(void) {}

那是行不通的。通过标记串联,定位宏 按字面意思处理,最终扩展为:

static void Unique___LINE__(void) {}

这可以吗?

c macros concatenation token
2个回答
211
投票

问题是,当您进行宏替换时,如果既没有应用字符串化运算符

#
也没有应用标记粘贴运算符
##
,预处理器只会递归地扩展宏。因此,您必须使用一些额外的间接层,您可以使用带有递归扩展参数的标记粘贴运算符:

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

然后,

__LINE__
在扩展
UNIQUE
期间扩展为行号(因为它不涉及
#
##
),然后在扩展
TOKENPASTE
期间进行标记粘贴。

还应该注意的是,还有

__COUNTER__
宏,每次计算时都会扩展为一个新整数,以防您需要在同一行上有
UNIQUE
宏的多个实例。注意:
__COUNTER__
受 MS Visual Studio、GCC(自 V4.3 起)和 Clang 支持,但不是标准 C。


2
投票

如何使用宏自动生成包含行号的唯一变量名称

这是一个通用答案,没有解决OP问题的狭隘细节,因为已经有足够的答案了。

我主要是从这里@Jarod42学到的,但也从这里@Adam.Rosenfield学到的。

#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__)

示例程序:

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 these lines which suppress the errors in order to
    // force the build errors to now show up so that we can see the
    // variable names in the compile-time error messages. 
    //
    // (void)counter_54;
    // (void)counter_55;
    // (void)counter_56;

    return 0;
}

样本输出:

请注意,故意产生的构建错误显示自动生成的变量名称为

counter_56
counter_55
counter_54
,如下所示!:

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]

完整输出:

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

另请参阅

  1. 我的答案在这里,我使用上面的
    MAKE_UNIQUE_VARIABLE_NAME()
    宏:在 C 和 C++ 编译时在错误消息中打印 (
    sizeof()
    ) 类型或变量的大小
© www.soinside.com 2019 - 2024. All rights reserved.