如果 "long" 和 "int" 的大小在平台上相同 - "long" 和 "int" 有任何不同吗?
If the size of "long" and "int" are the same on a platform - are "long" and "int" different in any way?
如果一个long int
和一个int
在一个平台上的表示是一样的,那么它们是否完全一样?根据 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);
}
我想同样的问题也适用于 short 和 int,如果它们恰好是相同的表示形式的话。
在讨论如何为没有 stdint.h 的嵌入式 C89 编译器定义类似于 int32_t
的 typedef 时出现了问题,即 int
或 long
,如果它会很重要。
类型long
和int
的等级不同。 long
类型的排名高于 int
类型的排名。因此,在使用 long
类型的对象和 int
类型的对象的二进制表达式中,最后一个总是转换为 long
.
类型
比较以下代码片段。
int x = 0;
unsigned int y = 0;
表达式x + y
的类型是unsigned int
。
long x = 0;
unsigned int y = 0;
表达式 x + y
的类型是 unsigned long
(由于通常的算术转换),前提是 sizeof( int )
等于 sizeof( long)
。
这在 C++ 中比在允许函数重载的 C 中非常重要。
在 C 中,例如当您使用 i/o 函数时必须考虑到这一点,例如 printf
以指定正确的转换说明符。
它们是不兼容的类型,你可以通过一个简单的例子看到:
int* iptr;
long* lptr = iptr; // compiler error here
所以在处理指向这些类型的指针时,它最重要。同样,有“严格的别名规则”使这段代码成为未定义的行为:
int i;
long* lptr = (long*)&i;
*lptr = ...; // undefined behavior
另一个微妙的问题是隐式提升。如果你有 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;
表示等价符号。)
即使在 long
和 int
具有相同表示的平台上,该标准也会允许编译器故意忽略将值存储到 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];
}
32 位 ARM 版本的 gcc 会将 int32_t
视为 long
的同义词,并忽略将 array1
的地址传递给 store_to_int32
的可能性导致该数组的第一个元素被写入,32 位版本的 clang 会将 int32_t
视为 int
的同义词,并忽略将 array2
的地址传递给 store_to_int32
可能会导致写入该数组的第一个元素。
可以肯定的是,标准中的任何内容都不会禁止编译器以这种方式行事,但我认为标准未能禁止这种盲目性源于以下原则:“东西越笨,就越不需要禁止它。
如果一个long int
和一个int
在一个平台上的表示是一样的,那么它们是否完全一样?根据 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);
}
我想同样的问题也适用于 short 和 int,如果它们恰好是相同的表示形式的话。
在讨论如何为没有 stdint.h 的嵌入式 C89 编译器定义类似于 int32_t
的 typedef 时出现了问题,即 int
或 long
,如果它会很重要。
类型long
和int
的等级不同。 long
类型的排名高于 int
类型的排名。因此,在使用 long
类型的对象和 int
类型的对象的二进制表达式中,最后一个总是转换为 long
.
比较以下代码片段。
int x = 0;
unsigned int y = 0;
表达式x + y
的类型是unsigned int
。
long x = 0;
unsigned int y = 0;
表达式 x + y
的类型是 unsigned long
(由于通常的算术转换),前提是 sizeof( int )
等于 sizeof( long)
。
这在 C++ 中比在允许函数重载的 C 中非常重要。
在 C 中,例如当您使用 i/o 函数时必须考虑到这一点,例如 printf
以指定正确的转换说明符。
它们是不兼容的类型,你可以通过一个简单的例子看到:
int* iptr;
long* lptr = iptr; // compiler error here
所以在处理指向这些类型的指针时,它最重要。同样,有“严格的别名规则”使这段代码成为未定义的行为:
int i;
long* lptr = (long*)&i;
*lptr = ...; // undefined behavior
另一个微妙的问题是隐式提升。如果你有 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;
表示等价符号。)
即使在 long
和 int
具有相同表示的平台上,该标准也会允许编译器故意忽略将值存储到 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];
}
32 位 ARM 版本的 gcc 会将 int32_t
视为 long
的同义词,并忽略将 array1
的地址传递给 store_to_int32
的可能性导致该数组的第一个元素被写入,32 位版本的 clang 会将 int32_t
视为 int
的同义词,并忽略将 array2
的地址传递给 store_to_int32
可能会导致写入该数组的第一个元素。
可以肯定的是,标准中的任何内容都不会禁止编译器以这种方式行事,但我认为标准未能禁止这种盲目性源于以下原则:“东西越笨,就越不需要禁止它。