C 根据类型转换的方式将类型转换包含在#定义的常量中是否合理';你打算用什么?
假设我有一堆未经想象的常量,这些常量在陀螺仪模块的头文件C 根据类型转换的方式将类型转换包含在#定义的常量中是否合理';你打算用什么?,c,C,假设我有一堆未经想象的常量,这些常量在陀螺仪模块的头文件gyro.h中给出了符号名称: #define GYRO_SPI_TIMEOUT 1000 在本例中,我的MCU的硬件抽象库使用uint32\u t表示毫秒数。在宏中添加类型信息,而不是分配空间并将其定义为const,是否明智 #define GYRO_SPI_TIMEOUT ((uint32_t) 1000) 这种方法的优点和缺点是什么?是的,经常这样做。事实上,臭名昭著的NULL指针通常是这样定义的: #定义空((void*)0)
gyro.h
中给出了符号名称:
#define GYRO_SPI_TIMEOUT 1000
在本例中,我的MCU的硬件抽象库使用uint32\u t
表示毫秒数。在宏中添加类型信息,而不是分配空间并将其定义为const
,是否明智
#define GYRO_SPI_TIMEOUT ((uint32_t) 1000)
这种方法的优点和缺点是什么?是的,经常这样做。事实上,臭名昭著的
NULL
指针通常是这样定义的:
#定义空((void*)0)
优点:无论全局常量支持者怎么说,您的宏现在都是类型安全的
缺点:如果您想以不安全的方式使用它,可以这样说:
short a=陀螺SPI超时代码>
你需要一个演员。但是,如果你不打算使用这种用法,这可能是件好事。 我会认为这是一件好事,尤其是确保正确的图形性(为此目的,<代码> 1000 U < /代码>就足够了)。算术类型在C中不是强类型的,因此,如果宏扩展具有正确的符号并被提升(即不小于int
),则大多数代码不会更改语义
<> P>有编译器的静态分析器和选项,但是,它会做更多的类型检查,不允许某些隐式转换,如果你的常量用你的头来表示代码,那么你的常量就好像是变量,那就太好了。(您可能需要向下滚动到显示“整数常量表达式宏”的位置)
与强制转换相比,这些宏的主要优点是使用它们定义的常量可以在更多上下文中使用。例如,((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
发布转换诊断,即使我将警告设置得尽可能高。当您可以使用1000U
时,很难看到有什么好处有任何实际原因需要进行额外转换吗?在大多数情况下,您不需要它:例如,对于赋值给我在uint32_t中使用nt,或将值传递给带有uint32_t
参数的函数。对于极少数需要强制转换的情况,可以显式添加它。@HansPassant:它不同。下面是一个示例:short s=((uint32_t)1000)
-不编译;short s=1000U
编译。看来您使用的UINTN\u C
宏是正确的。尽管您的上一个语句似乎与文档不一致。宏将扩展为整数常量1234UL
(或者任何Ls的组合将使其至少宽32位)。当您将其分配给较短的值时,应该会生成一个警告,对吗?@josaphatv大多数编译器都会默默地接受short a=
,而不管整型文字的后缀是什么,除非该分配实际更改了数值。因此,short a=1234UL;
毫无怨言地通过,但short a=65537UL;
警告。@josaphatv……经过实验,我也无法说服gcc警告短a=((无符号长)1234)
,即使设置了荒谬的攻击性警告也不行。建议使用[U]INT\U C
在这里并没有阐明一个要点:UINT32\U C(1234)
不创建类型uint32\u t
,而是uint32\u t
。