如何在跨文件预处理时获取唯一值

时间:2014-08-08 13:13:23

标签: c macros embedded c-preprocessor

问题

我需要一种使用预处理器指令生成唯一值的方法。目的是每次调用宏时,它都会有一个唯一的整数标识符。但它应该保留它跨文件的价值。有点像预处理器计数器,用于调用函数的次数。

进一步信息

我使用的宏是:

#define LOG_MSG(a) log_msg(?)
  1. 'a'是用户想要打印的字符串。
  2. log_msg是用于在UART上打印消息的自定义函数
  3. '?'如果我需要帮助的部分。
  4. 此宏仅在一个地方定义。在预处理阶段,'?'将被唯一标识符替换。我们这样做是为了减少字符串带来的开销,因为此代码将在嵌入式设备上运行。在预处理之后,将提取标识符和相关字符串,并创建一个将映射它们的表(这将在应用程序端)。

    由于这将用于多个文件,我想要一种方法来为多个文件中的每次使用生成唯一标识符(整数而不是字符串)(每个唯一字符串的标识符将是理想的但没必要。)

    有什么想法吗?

    如果有任何遗漏或不完整的信息,请提及

    备注

    __COUNTER__是我尝试的第一件事,但它不适用于文件 __FILE__会给我一个违背目的的字符串。

    有人提到使用唯一文件标识符。但我不想静态分配这些。我们正在使用CCS(它基于Eclipse Kepler构建)来构建此代码。所以我想我们可以在构建系统中添加一些内容来执行@embedded_guy所提到的内容。有谁知道怎么做?

    由于

4 个答案:

答案 0 :(得分:5)

通常,不可能确保始终为每个宏扩展生成唯一标识符。

您可以使用内置__LINE__宏来解决问题,假设每行最多使用一次宏。但是,由于您需要在多个文件中使用它,因此您需要手动定义另一个每个文件唯一的宏。例如,在 foo.c 的顶部:

#define FILE_NAME foo
#include "log.h" // or whatever defines `LOG_MSG`

然后,您可以在FILE_NAME__LINE__上使用宏​​连接来生成唯一标识符。

如果只是一个字符串就足够了(而不是实际的变量),你也可以使用__FILE__宏,并结合__LINE__的“字符串化”版本,如下所示:

#define FILE_LINE(x, y)  FILE_LINE_(x, y)
#define FILE_LINE_(x, y) x ## #y
#define LOG_UNIQUE_ID_STRING FILE_LINE(__FILE__, __LINE__)

同样,这假设每个逻辑行最多调用一次。

某些编译器还支持__COUNTER__宏,可用于代替__LINE__,这允许每个逻辑行进行多次调用(但同样,您需要将其与其他内容组合使用,因为__COUNTER__在多个翻译单元(也称为C文件)中并不是唯一的。)

答案 1 :(得分:4)

我建议使用标准C预处理器无法实现您的解决方案,并且需要不同的解决方案。此外,建议的解决方案还不完整 - 单独生成UID是不够的,您需要能够将该UID与原始字符串相关联,并且不清楚如何实现该目标。

编写一个单独的自定义预处理器似乎更简单,该预处理器在源代码中搜索LOG_MSG( <some_string> )的实例,提取<some string>并用预处理器生成的UID替换它,并构建一个字符串表供主人使用。

宏定义将是:

#define LOG_MSG(a) log_msg( a )

但是,在原始的未经预处理的代码中,a将是一个文字字符串,而log_msg()将被定义为log_msg( int a )

在编译之前,执行预处理器将是必要的预构建步骤。大多数IDE支持可用于集成此工具的预构建和预编译步骤,或者作为make规则添加例如足够简单。

任何编译未经过预处理的代码的尝试都将无法编译,因为参数将是字符串文字而不是整数,因此不存在省略执行预处理的危险。

您唯一需要确保的是,您在主机上使用与目标代码的特定构建相关联的字符串表 - 但无论如何您都遇到了这个问题。

请注意,它仅在a是文字字符串时才有效 - 但在任何情况下都是最初提出的解决方案的情况。您的预处理器可以检查并发出错误,但未传递文字字符串。

答案 2 :(得分:1)

虽然它滥用了预处理器指令,但您可以生成here提到的伪随机数,并与另一个宏__FILE____LINE__连接,以生成唯一字符串。

__COUNTER__是一种简单但非标准的做法。

Boost Preprocessor library也很有用。例如,以下“myheader.h”头文件将在包含它的任何位置输出唯一标签。

#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/slot/slot.hpp>

#if !defined(MYUNIQID)
#define MYUNIQID
#define BOOST_PP_VALUE 1
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#else
#define BOOST_PP_VALUE BOOST_PP_INC(BOOST_PP_SLOT(1))
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#endif


BOOST_PP_CAT(__FILE__, BOOST_PP_SLOT(1)):

您的唯一ID将在#include "myheader.h"

的任何位置生成

答案 3 :(得分:1)

为什么不试试#line预处理程序指令?您可以为每个源文件指定唯一的起始行号,然后使用__LINE__作为唯一标识符。您必须确保在每个文件之间保留足够的行,以便所有数字保持唯一。这是一个例子:

<强> file_identifiers.h

/* Maintain 10,000 lines between each file.  If a file has greater
   than 10,000 lines then these numbers will have to be increased. */
#define FILE_IDENTIFIER_MAIN    10000
#define FILE_IDENTIFIER_LOG     20000

<强> log.h

#include <stdint.h>
void log_msg (int32_t unique_id);
void log_test (void);

<强> log.c

#include <stdio.h>
#include "log.h"
#include "file_identifiers.h"

#line FILE_IDENTIFIER_LOG   //log.c now starts with line 20000

void log_msg (int32_t unique_id)
{
    printf("Unique ID: %d\r\n", unique_id);
}

void log_test (void)
{
    log_msg(__LINE__);
}

<强>的main.c

#include <stdlib.h>
#include "file_identifiers.h"
#include "log.h"

#line FILE_IDENTIFIER_MAIN    //main.c now starts with line 10000

int main (void)
{
    log_msg(__LINE__);
    log_test();
    exit (EXIT_SUCCESS);
}

<强>输出

Unique ID: 10003
Unique ID: 20008