我有一个行为,我不明白,我试图构造一个64整数从一个数组的字节从大到小的endian。
uint64_t u;
uint8_t bytes[2];
bytes[1] = 0xFF;
u = bytes[1] << 24 ;
dump_bytes_as_hex( &u, 8 );
00 00 00 FF FF FF FF
u = ( (uint16_t) bytes[1]) << 24 ;
dump_bytes_as_hex( &u, 8 );
00 00 00 FF FF FF FF
u = ( (uint32_t) bytes[1]) << 24 ;
dump_bytes_as_hex( &u, 8 );
00 00 00 00 00 00 00 00 00
我不明白为什么只有当我转换成一个比移位大小更多的类型时,它才能给予我正确的结果。我尝试了不同的价值观:
- 0xFF-1给予相同的坏结果
*100给予正确的结果,无需转换
我想知道规则是什么?为什么100会给予正确的值。
谢谢大家。
编辑:
下面是一个可复制的示例:
#include <stdio.h>
#include <stdint.h>
void dump_bytes_as_hex( uint8_t* b, int count )
{
FILE* f;
f = stdout;
for( int c = 0; c < count; ++c )
{
fprintf( f, "%02X", b[c] );
fputc( ' ', f );
}
fputc( '\n', f );
fflush( f );
}
void test( uint8_t i )
{
uint64_t u;
uint8_t bytes[2];
fprintf( stdout, "Test with %d\n", (int) i );
u = 0;
bytes[1] = i;
u = bytes[1] << 24 ;
dump_bytes_as_hex( (uint8_t*) &u, 8 );
u = ( (uint16_t) bytes[1]) << 24 ;
dump_bytes_as_hex( (uint8_t*) &u, 8 );
u = ( (uint32_t) bytes[1]) << 24 ;
dump_bytes_as_hex( (uint8_t*) &u, 8 );
fprintf( stdout, "\n\n");
}
int main()
{
test( 0xFF );
test( 0xFF -1 );
test( 100 );
return 0;
}
2条答案
按热度按时间hyrbngr71#
我想知道规则是什么?
事实上,对于你的具体例子,没有任何规则。..
...还有...
...如果您的
int
是32位宽。移位操作的左操作数是 * 通常的算术转换 *,这将具有将左操作数的8位或16位无符号值转换为(
signed
)int
并产生该类型的结果的效果。如果有符号类型(*i.即 *int
)不能表示为该类型的值,则行为未定义。这就是为什么我说没有规则的原因。在您的特定情况下,您的实现似乎是通过将左操作数重新解释为无符号32位值来执行移位,将结果重新解释为(有符号)int。然后,对类型
uint64_t
的赋值(通常)通过添加264将负右操作数转换为tyuint64_t
,以将其带入该类型的范围。(此类转换仅用于转换为无符号整数类型,而不用于转换为有符号整数类型。你正在使用一个little-endian系统,并按内存顺序打印出结果字节,所以你得到:00 00 00 FF FF FF FF
另一方面,如果在32位系统上将移位操作数转换为
uint32_t
。.....则结果类型不受标准算术转换的影响,并且转换的结果具有该类型。
uint32_t
可以表示移位(0xff000000
)的算术结果,因此这实际上是结果。当转换为uint64_t
类型进行赋值时,该值不变。一般建议:在使用按位操作时使用无符号类型,尤其是在执行移位时。
k3bvogb12#
将结果赋给的变量的类型(如果有的话)是无关的。
只有当左操作数的类型是整数提升后可以保存结果的类型时,它才有效。
(uint8_t)0xFF << 24
在
int
类型为16的环境中。.32位,则(uint8_t)0xFF
被提升为int
。0xFF × 224太大,无法容纳在int
中。作为有符号类型,这会导致未定义的行为。在
int
类型为33+位的环境中,(uint8_t)0xFF
将升级为int
。0xFF × 224适合int
。这个管用(uint16_t)0xFF << 24
在
int
类型为16的环境中。.24位,则(uint16_t)0xFF
将产生16位unsigned int
。左移大于或等于操作数大小的位数是未定义的行为。在
int
类型为25的环境中。.32位,则(uint16_t)0xFF
产生int
。0xFF × 224太大,无法容纳在int
中。作为有符号类型,这会导致未定义的行为。在
int
类型为33+位的环境中,(uint16_t)0xFF
将产生int
。0xFF × 224适合int
。这个管用(uint32_t)0xFF << 24
0xFF × 224适合32位无符号整数。这个管用
因此,要生成
uint64_t
,您需要或
但是,外部强制转换可以在这里删除,因为赋值将隐式执行此强制转换。