6

背景

在微控制器代码中,我使用的是生产者提供的库,其中定义了许多常量。如果我的一些常量(与微控制器外部的组件共享,带有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_ttypedef 并且它仍然会被强制转换int为例如。

问题

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

我考虑过定义uint8_t为某物并在 之后取消定义它#if,但我不知道如何避免转换性质(Y)X并将其转换为算术表达式。

4

5 回答 5

11

这是一个改进的版本(第一个版本在下面)。这不取决于演员阵容uint8_t;它将与FLASH_BLOCK_SIZE表单的任何替换列表一起使用((some type) number)

#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

在编写代码时,我更喜欢静态断言,但上面的代码可以满足您在预处理器中的要求。

于 2013-10-16T14:53:10.717 回答
5

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

STATIC_ASSERT(FLASH_BLOCK_SIZE == MYPROG_BLOCK_SIZE);

以下是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。

于 2013-10-16T14:45:53.353 回答
2

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

#define FLASH_BLOCK_SIZE ((uint8_t)+64)

注意到里面的小加号了吗?

预处理器将它不知道的类型名替换为 0,因此这在两种情况下都适用。(无论如何,预处理器应该做所有的算术[u]intmax_t

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

于 2013-10-16T14:44:53.530 回答
1

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

#if 64 != ((uint8_t)64)

相当于:

#if 64 != ((0)64)

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

所以给出:

#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其他地方使用。

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

#define FLASH_BLOCK_SIZE 64

可以肯定的是,您需要检查所有引用FLASH_BLOCK_SIZE. (评估sizeof FLASH_BLOCK_SIZE将是一个问题,但我敢打赌你永远不会那样做。)

于 2013-10-16T14:49:11.820 回答
0

我知道问题线程很旧,但是我今天遇到了...如果您不想或无法更改#define,其他答案很好,但如果您可以访问#define,我建议使用 for pre - 处理器操作(#if - #else - #endif)而不是:

#define FLASH_BLOCK_SIZE ((uint8_t)64)

使用这个定义:

#define FLASH_BLOCK_SIZE (64U)

这样演员阵容仍然存在,编译器不会“混淆”。

于 2016-11-03T11:27:24.680 回答