假设我在陀螺仪模块gyro.h
的头文件中有一些非魔法的常量,这些常量已被赋予符号名称:
#define GYRO_SPI_TIMEOUT 1000
在这种情况下,我的MCU的硬件抽象库使用uint32_t
的毫秒数。代替分配空间并将其定义为const
,在宏中添加类型信息是否明智?
#define GYRO_SPI_TIMEOUT ((uint32_t) 1000)
这种方法的好处和缺点是什么?
答案 0 :(得分:3)
我认为这是一件好事,特别是确保正确的签名(为此,1000u
就足够了)。算术类型在C中没有强类型,因此如果宏扩展具有正确的签名并且被提升(即,不小于int
),大多数代码都不会改变语义。
然而,编译器有静态分析器和选项,它们会进行更多的类型检查并禁止某些隐式转换,如果你的常量表现得就好像它们是使用标头的代码的大多数用途的变量那样会很好。
答案 1 :(得分:3)
您可能需要考虑使用[U]INT<n>_C
macros from stdint.h
(您可能需要向下滚动到“整数常量表达式的宏”)。
这些宏的主要优点是,使用它们定义的常量可以在更多的上下文中使用。例如,((uint32_t)1234)
无法显示在#if
表达式中,UINT32_C(1234)
可以显示。
请注意,除非转换实际更改了值,否则大多数C编译器都不会抱怨涉及缩小转换的常量表达式的赋值。例如,给定
short a = 1234UL;
short b = ((unsigned long)1234);
short c = 65537UL;
short d = ((unsigned long)65537);
gcc 4.9和clang 3.5发布有关c
和d
的转换仅的诊断信息,即使我将警告提高到最高位置也是如此。
答案 2 :(得分:0)
是的,经常这样做。实际上,臭名昭着的NULL
指针通常定义如下:
#define NULL ((void*)0)
优势:无论全球常量支持者说什么,您的宏现在都是类型安全的。
缺点:如果你想以非类型安全的方式使用它,比如说:
short a = GYRO_SPI_TIMEOUT;
你需要演员。但是,如果你不打算这种用法发生,这可能是一件好事。