我正在使用arm-none-eabi-gcc
7.4来为基于ARM Cortex-M4的微控制器(特别是EFM32WG940)编译一个“裸机”程序。
据我所知,sizeof(int)
和sizeof(long int)
以及它们的未签名副本都是4
。实际上,您必须键入long long int
才能获得64位整数(或int64_t
),因此long int
似乎完全多余。
在这种环境下,为什么将__UINT32_TYPE__
predefined macro定义为long unsigned int
?
是否可以将uint32_t
更改为unsigned int
?
通常这不会打扰我,但是由于printf
,这会使-Wformat
很难受。考虑类似printf("hello %u\n", i);
的事物(假设i
是uint32_t
)
这给了我一个警告,因为%u
期望unsigned
但uint32_t
是unsigned long
。显然,我可以将其更改为%lu
,但是在x86上编译时,相同的代码将给我警告。
编辑:
是的,使-Wformat
静音的一种方法是像这样使用inttypes.h
中的format macros:printf("hello %" PRIu32, i);
虽然实际上并不能回答我的问题,但最多如果代码不是那么丑陋,并且某些静态分析器没有问题,就可以了。
我不想了解我所有的printf调用,而是想了解为什么在此平台上uint32_t
必须是unsigned long int
而不是unsigned int
,以及如何进行更改。
答案 0 :(得分:1)
据我所知,
sizeof(int)
和sizeof(long int)
以及它们的 未签名的副本均为4。实际上,您必须输入long long int
才能获得 64位整数(或int64_t
),因此long int
似乎是 完全多余的。
C语言没有指定标准整数类型的确切宽度。而是指定每个值必须代表的最小值范围。这允许以自然的方式针对不同体系结构的目标编写C。特别是,符合的实现可以为int
提供少至15个值位,而long int
必须至少具有31个值,而long long int
必须至少具有63个值。有符号整数类型也有一个符号位,而无符号对应物有一个附加值位。 (尽管很少见,但这些都可能有填充位。)因此,long int
并不是多余的,至少在语义上不是这样。
在这种环境下,为什么
__UINT32_TYPE__
是预定义的宏 定义为long unsigned int
?
首先,__UINT32_TYPE__
是一个glibc实现细节。因此,提出的对该问题的唯一合理答案是“因为unsigned long int
是为uint32_t
选择的类型”。但是我实际上是问您为什么首先选择了该类型。在这里,我无法明确说明GCC / glibc开发人员做出决定的原因,但我想我会在他们试图支持多种架构的地方做出同样的选择。
由于保证long int
和unsigned long int
分别具有至少31和32个值位(而int
和unsigned int
不是),所以长版本是自然的实际上满足其要求的平台上的[u
int32_t
的选择(完全 共32位,无填充位,带符号的版本实现为二进制补码) 。对于某些受支持的体系结构,长版本是唯一正确的选择,对于其余大多数而言,它们也是可接受的选择。通过选择长版本,glibc仅需要对一部分64位平台(也许是少数具有奇数整数类型的平台)设置例外。
对于int
和unsigned int
满足以下条件的int32_t
和uint32_t
是为uint32_t
和unsigned int
选择的类型没有任何要求,也没有任何期望的理由除非它们是满足要求的 only 可用类型。
是否可以将
uint32_t
更改为unsigned int
?
您的C代码没有统一的方法来更改实现提供的printf
的定义。您可以尝试破解C实现以进行更改,也可以选择完全不同的实现,但是任何重新定义已定义类型的尝试都会产生未定义的行为(并且可能(但不一定)被编译器拒绝)。 / p>
在使用带格式化I / O函数的显式宽度类型时,处理类型可变性的标准方法是使用the macros provided for that purpose,您已经知道了。另外,如果您满意知道所有感兴趣平台所涉及的类型的适用定义,则可以直接编写适当的格式。或者,您可以直接使用您选择的标准类型( eg scanf
),或者对于%lu
但不能unsigned long
,将参数强制转换为与格式。
不要轻视使用标准类型而不是显式宽度类型别名的替代方法。前者是足够的一种更平滑的替代方法-不需要任何特殊的头,并且可以与所有标准库函数实现平滑的互操作性。
很明显,我可以将其更改为
int32_t
,但是相同的代码将给我一个 在x86上编译时发出警告。
也许会,也许不会。对于32位x86,类型{{1}}在glibc上也是32位宽。我不确定是否是为此{{1}}选择的类型,但这是可行的替代方法之一。即使对于某些64位平台,例如Win64,也是如此。对于两种选择都可行的任何给定平台,您可能会发现一些选择其中一种的实现,而某些选择了另一种。