为什么在arm-none-eabi GCC上将uint32_t键入为unsigned long,以及如何更改它?

时间:2019-04-21 11:21:07

标签: c gcc arm cortex-m

我正在使用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);的事物(假设iuint32_t) 这给了我一个警告,因为%u期望unsigneduint32_tunsigned long。显然,我可以将其更改为%lu,但是在x86上编译时,相同的代码将给我警告。

编辑:

是的,使-Wformat静音的一种方法是像这样使用inttypes.h中的format macrosprintf("hello %" PRIu32, i);虽然实际上并不能回答我的问题,但最多如果代码不是那么丑陋,并且某些静态分析器没有问题,就可以了。

我不想了解我所有的printf调用,而是想了解为什么在此平台上uint32_t必须是unsigned long int而不是unsigned int,以及如何进行更改。

1 个答案:

答案 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 intunsigned long int分别具有至少31和32个值位(而intunsigned int不是),所以长版本是自然的实际上满足其要求的平台上的[u int32_t的选择(完全 共32位,无填充位,带符号的版本实现为二进制补码) 。对于某些受支持的体系结构,长版本是唯一正确的选择,对于其余大多数而言,它们也是可接受的选择。通过选择长版本,glibc仅需要对一部分64位平台(也许是少数具有奇数整数类型的平台)设置例外。

对于intunsigned int满足以下条件的int32_tuint32_t是为uint32_tunsigned 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,也是如此。对于两种选择都可行的任何给定平台,您可能会发现一些选择其中一种的实现,而某些选择了另一种。