在预处理器中从常量中删除强制转换

背景

在微控制器代码中,我使用的是生产者提供的库,其中定义了许多常量。 如果我的一些常量(与微控制器之外的组件共享,使用git-subtree )和微控制器常量之间存在不匹配,我试图给出错误。

例如,库定义:

 #ifdef SOME_PARTICULAR_MODEL #define FLASH_BLOCK_SIZE ((uint8_t)64) /* else, other models */ #endif 

在某处,在微控制器代码和PC上编译的一些代码之间共享的标题中,我有例如:

 #define MYPROG_BLOCK_SIZE 64 

为了确保这些常量匹配,在微控制器代码中,两个常量都存在,我有:

 #if MYPROG_BLOCK_SIZE != FLASH_BLOCK_SIZE #error "mismatch between actual block size and defined block size" #endif 

这是为了确保代码是否曾被移植到更大的微控制器,共享头也将被更新。

问题

问题是这会减少到:

 #if 64 != ((uint8_t)64) 

我不确定它是否是有效的C ,但仍然使编译器窒息。 测试,我发现问题不在于uint8_t是一个typedef,并且它仍然会被一个强制转换为int ,例如。

问题

有没有办法从定义为((uint8_t)64)的值中删除(uint8_t)部分? 如果没有,有没有办法改变它,所以表达式变成一个没有演员?

我想过将uint8_t定义为某些内容并在#if之后取消定义它,但我无法弄清楚如何避免(Y)X转换性质并将其转换为算术表达式。

这是一个改进版本(第一个版本在下面)。 这个不依赖于演员是uint8_t ; 它将适用于表单((some type) number)任何FLASH_BLOCK_SIZE替换列表。

 #define MYPROG_BLOCK_SIZE 64 #define FLASH_BLOCK_SIZE ((uint8_t)64) #define B(x) #define C(x) B x #define D(x) C x #if MYPROG_BLOCK_SIZE != D(FLASH_BLOCK_SIZE) #error "mismatch between actual block size and defined block size" #endif 

这是原始版本:

 #define MYPROG_BLOCK_SIZE 64 #define FLASH_BLOCK_SIZE ((uint8_t)64) #define uint8_t #define Helper(x) x #define Deparenthesize(x) Helper x #if MYPROG_BLOCK_SIZE != Deparenthesize(Deparenthesize(FLASH_BLOCK_SIZE)) #error "mismatch between actual block size and defined block size" #endif #undef uint8_t 

在编写代码时,我更喜欢静态断言,但上面做了你在预处理器中请求的。

解决方案是使用静态断言。 使用良好的STATIC_ASSERT宏,您可以在头文件中的文件范围内放置一个静态断言:

 STATIC_ASSERT(FLASH_BLOCK_SIZE == MYPROG_BLOCK_SIZE); 

以下是STATIC_ASSERT宏的定义STATIC_ASSERT

 #define CAT(x, y) CAT_(x, y) #define CAT_(x, y) x ## y #define STATIC_ASSERT(expr) \ extern int CAT(static_assert_failed_, __LINE__)[(expr) ? 1 : -1] 

对于一些编译器(例如,IAR),您将static_assert作为内置编译器。 static_assert也出现在C11中,但遗憾的是没有很多嵌入式C编译器支持C11。

对于任何typedef,您可以通过更改为arrount

 #define FLASH_BLOCK_SIZE ((uint8_t)+64) 

注意那里的小加号?

预处理器将其不知道的类型名称替换为0,因此这在两个上下文中都有效。 (无论如何,预处理器应该在[u]intmax_t进行所有算术运算)

对于您使用的实际类型,所有这些都没有多大意义。 没有uint8_t常量这样的东西。 一旦评估它们,所有比int窄的类型的表达式都将转换为int 。 所以它可能没有任何区别。

在宏替换之后,预处理器表达式可以具有defined identifierdefined ( identifier )的formsdefined ( identifier )子表达式。 除此之外,标识符和关键字没有意义; 每个标识符或关键字都替换为0 。 所以这:

 #if 64 != ((uint8_t)64) 

相当于:

 #if 64 != ((0)64) 

这是一个语法错误。 它是一个typedef的事实不是问题; 像int这样的关键字得到相同的处理。

所以给出:

 #define FLASH_BLOCK_SIZE ((uint8_t)64) 

您不能在预处理器表达式中使用FLASH_BLOCK_SIZE

我能想到的最好的解决方案是改变你的定义:

 #define FLASH_BLOCK_SIZE_NUM 64 #define FLASH_BLOCK_SIZE ((uint8_t)FLASH_BLOCK_SIZE_NUM) 

然后,您可以在预处理器表达式中使用FLASH_BLOCK_SIZE_NUM在其他位置使用FLASH_BLOCK_SIZE_NUM

另一方面,你真的需要(int8_t)演员吗? 算术表达式在许多上下文中被隐式转换,通常是适当的类型。 在许多情况下, (uint8_t)无论如何都会被提升为int 。 你很可能只是放弃演员并使用:

 #define FLASH_BLOCK_SIZE 64 

当然,您需要检查引用FLASH_BLOCK_SIZE所有代码。 (评估sizeof FLASH_BLOCK_SIZE问题,但我打赌你永远不会这样做。)

我知道问题线程是旧的,但是我今天遇到了…如果你不想或不能改变#define,其他答案都很棒,但是如果你有权访问#define,我建议使用pre – 处理器操作(#if – #else – #endif)而不是:

 #define FLASH_BLOCK_SIZE ((uint8_t)64) 

使用此定义:

 #define FLASH_BLOCK_SIZE (64U) 

这种方式仍然存在,并且编译器不会“混淆”。