如果“long”和“int”的大小在一个平台上相同——“long”和“int”有什么不同吗?

Vil*_*elm 50 c types integer representation

如果 along int和 aint在平台上的表示相同,它们是否严格相同?根据 C 标准,这些类型在平台上的行为是否有任何不同?

例如。这是否总是有效:

int int_var;
long long_var;

void long_bar(long *l);
void int_bar(int *i);

void foo() 
{
    long_bar(&int_var); /* Always OK? */
    int_bar(&long_var);
}
Run Code Online (Sandbox Code Playgroud)

我想同样的问题适用于 short 和 int,如果它们碰巧是相同的表示。

在讨论如何为int32_t没有 stdint.h 的嵌入式 C89 编译器定义一个-like typedef时出现了问题,即 as intorlong以及是否重要。

Lun*_*din 41

它们不是兼容的类型,您可以通过一个简单的示例来查看:

int* iptr;
long* lptr = iptr; // compiler error here
Run Code Online (Sandbox Code Playgroud)

所以在处理指向这些类型的指针时最重要。同样,有“严格的别名规则”使此代码行为未定义:

int i;
long* lptr = (long*)&i;
*lptr = ...;  // undefined behavior
Run Code Online (Sandbox Code Playgroud)

另一个微妙的问题是隐式提升。如果您有,some_int + some_long那么该表达式的结果类型是long. 或者,如果任一参数是无符号的,unsigned long. 这是因为通过通常的算术转换进行整数提升,请参阅隐式类型提升规则。大多数时候应该无关紧要,但是这样的代码会失败:_Generic(some_int + some_long, int: stuff() )因为long表达式中没有子句。

通常,在类型之间分配值时,应该没有任何问题。在 的情况下uint32_t,它对应于哪种类型并不重要,因为uint32_t无论如何您都应该将其视为单独的类型。我会选择long与小型微控制器的兼容性,哪里typedef unsigned int uint32_t;会坏。(显然,typedef signed long int32_t;对于签名的等价物。)


Vla*_*cow 16

种类longint等级不同。类型long的等级高于类型的等级int。所以在存在中使用的类型的对象的二进制表达式long和类型的对象int的最后一个总是被转换到该类型long

比较以下代码片段。

int x = 0;
unsigned int y = 0;
Run Code Online (Sandbox Code Playgroud)

表达式的类型x + yunsigned int

long x = 0;
unsigned int y = 0;
Run Code Online (Sandbox Code Playgroud)

表达式的类型x + yunsigned long(由于通常的算术转换)sizeof( int )等于sizeof( long)

这在 C++ 中比在允许函数重载的 C 中非常重要。

在 C 中,您必须考虑到这一点,例如,当您使用 i/o 函数时,例如printf指定正确的转换说明符。


sup*_*cat 5

即使在地方平台longint具有相同的表示,该标准将允许编译器是故意无视这种可能性,即一个值存储到的行为long*可能会影响一个企业的价值int*,反之亦然。给出类似的东西:

#include <stdint.h>

void store_to_int32(void *p, int index)
{
    ((int32_t*)p)[index] = 2;
}
int array1[10];
int test1(int index)
{
    array1[0] = 1;
    store_to_int32(array1, index);
    return array1[0];
}
long array2[10];
long test2(int index)
{
    array2[0] = 1;
    store_to_int32(array2, index);
    return array2[0];
}
Run Code Online (Sandbox Code Playgroud)

的gcc的32位ARM版本将治疗int32_t同义与long和忽略传递到地址的可能性array1,以store_to_int32可能导致该阵列的第一个元素将被写入,并铛的32位版本将把int32_t与同义int和忽略传递array2to的地址store_to_int32可能导致该数组的第一个元素被写入的可能性。

可以肯定的是,标准中的任何内容都不会禁止编译器以这种方式行事,但我认为标准未能禁止这种盲目性源于“某事越愚蠢,就越不需要禁止它”的原则。