我正在尝试使用C ++将4个字节转换为整数。
这是我的代码:
int buffToInteger(char * buffer)
{
int a = (int)(buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]);
return a;
}
上述代码几乎适用于所有情况,例如:
当我的缓冲区为:"[\x00, \x00, \x40, \x00]"
时,代码将按预期返回16384
。
但是当缓冲区充满:"[\x00, \x00, \x3e, \xe3]"
时,代码将无法正常工作并返回"ffffffe1"
。
有谁知道为什么会这样?
答案 0 :(得分:19)
您的buffer
包含已签名的字符。实际上,buffer[0] == -29
在转换为int
后会被转换为0xffffffe3
,并依次(0x3e << 8) | 0xffffffe3 == 0xffffffe3
。
您需要确保将buffer
个字节解释为unsigned
,方法是将buffer
声明为unsigned char *
,或明确转换:
int a = int((unsigned char)(buffer[0]) << 24 |
(unsigned char)(buffer[1]) << 16 |
(unsigned char)(buffer[2]) << 8 |
(unsigned char)(buffer[3]));
答案 1 :(得分:5)
在表达式buffer[0] << 24
中,值24为int
,因此在执行转换之前,buffer[0]
也会转换为int
。
在您的系统上,char
显然已签名,然后在转换为int
后进行签名扩展。
答案 2 :(得分:2)
在轮班中对签名的int进行隐含的提升。 那是因为char(显然)在你的平台上签名(常见的东西)和&lt;&lt;隐含地促进整数。事实上,这一切都不会起作用,因为&lt;&lt; 8(及更高)会磨掉你所有的位!
如果您因使用签名字符缓冲区而陷入困境,这将为您提供所需内容:
#include <iostream>
#include <iomanip>
int buffToInteger(char * buffer)
{
int a = static_cast<int>(static_cast<unsigned char>(buffer[0]) << 24 |
static_cast<unsigned char>(buffer[1]) << 16 |
static_cast<unsigned char>(buffer[2]) << 8 |
static_cast<unsigned char>(buffer[3]));
return a;
}
int main(void) {
char buff[4]={0x0,0x0,0x3e,static_cast<char>(0xe3)};
int a=buffToInteger(buff);
std::cout<<std::hex<<a<<std::endl;
// your code goes here
return 0;
}
注意有符号值的位移。促销活动不仅可以添加字节,还可以转换价值。
例如,这里的问题是您不能直接使用static_cast<unsigned int>(buffer[1])
(等),因为它会将signed char值转换为signed int,然后将该值重新解释为unsigned。
如果有人问我所有隐含的数字转换都很糟糕。没有任何计划应该有这么多,他们会成为一件苦差事。从C继承的C ++中的软性会导致各种各样的问题远远超过它们的价值。 它在C ++中更糟糕,因为它们使已经令人困惑的重载规则更加令人困惑。
答案 3 :(得分:2)
unsigned byte buffer[4];
int a;
a = *(int*)&buffer;
答案 4 :(得分:0)
我认为也可以通过使用memcpy
来完成:
int buffToInteger(char* buffer)
{
int a;
memcpy( &a, buffer, sizeof( int ) );
return a;
}
这比原始文章中提到的示例要快得多,因为它仅按“原样”对待所有字节,并且无需执行任何操作,例如移位等。 它也不会引起任何未签名的问题。