【问题标题】:Junk appearing when converting to char from int32 in C/C++在 C/C++ 中从 int32 转换为 char 时出现垃圾
【发布时间】:2019-05-01 18:26:37
【问题描述】:

我正在使用一个简单的代码将 uint32_t 变量转换为 char。

uint32_t len = 4 + data.length(); //data is a string
char pop1 = len & 0xff;
char pop2 = (len >> 8) & 0xff;
char pop3 = (len >> 16) & 0xff;
char pop4 = (len >> 24) & 0xff;     //also tried the same thing with memcpy

printf("%02x \n",pop1);
printf("%02x \n",pop2);
printf("%02x \n",pop3);
printf("%02x \n",pop4); 

输出:

ffffff81
02
00
00

我不明白为什么垃圾会被添加到第一个字节。当我改用unsigned char 时,不会添加任何垃圾。据我了解,char 和 unsigned char 都是 8 位,那么为什么 char 被视为 32 位值。我在 64 位 Windows 机器上使用 VS2015。我想将 char 数组用于 WinSock2 的发送函数。

send(ConnectSocket, sendbuf, size_to_send, 0); // sendbuf is a char array

【问题讨论】:

  • TL/DR:在进行位操作时使用unsigned 变量。你的charsigned
  • @Slava:我希望有一个原件,这是一个副本,但问题不是它。问为什么会出现这些额外的位与问如何避免它们是不同的,后一个问题的答案并不能回答这个问题。

标签: c++ c sockets type-conversion


【解决方案1】:

当一个小整数类型的值(如char)作为参数传递给可变参数函数(如printf)时,它是promotedint

如果小号为signed,此促销可以包含符号扩展

two's complement 系统上(长期以来,绝大多数计算机都是如此),这意味着int 将用1 位填充,当以十六进制打印为unsigned int 时,将显示为@987654330 @。

简单的解决方案是不使用char,但最好为您的变量使用uint8_t 或显式unsigned char 类型。

【讨论】:

  • 仅供参考,我对 dbush 的回答投了赞成票,因为它更准确、更准确地将促销描述为 的转换。 “符号扩展”是对值的表示的操作,它不是 C 标准所规定的。
【解决方案2】:

在表达式中使用时,char 首先提升int。因此,如果char 的值为负,则在转换为int 时会保留该值,这就是您在打印时看到的内容。

您可以将该值强制转换为 unsigned char 以使其具有正值,或者您可以在 %x 格式说明符上使用 hh 修饰符使其将该值视为 unsigned char

printf("%02hhx \n",pop1);
printf("%02hhx \n",pop2);
printf("%02hhx \n",pop3);
printf("%02hhx \n",pop4);

【讨论】:

  • 此外,将%02x 用于将char 提升为int 的参数与类型不匹配,因为%02x 需要unsigned int 参数。
【解决方案3】:

想想所有发生的类型更改和转换。至少有 4 个。

0xffint 转换为uint32_t,然后出现&。这里没有问题。

len & 0xff;

然后将该结果分配给char,在 OP 的情况下为 已签名 char。这会将超出范围的0x81 (129) 分配给char --> 实现定义的行为。一个常见的结果只是传递最小的位。

char pop1 = len & 0xff;

为什么 char 被视为 32 位值 (?)

尚未将其视为 32 位 unsigned 值,而是视为 8 位 signed 值。

然后代码将char pop1(可能值为-127)传递给printf();,并产生一个默认参数提升作为...函数的参数。 printf() 收到一个值为 -127 的 int

printf(...,pop1);

printf("%02x \n",pop1); 需要 unsigned 而不是 int。由于 -127 的值不能同时表示为 intunsigned,(c11 §6.5.2.2 6),转换说明符对该参数无效,结果是 未定义的行为 (UB)。 (§7.21.6.1 9)。通常发生的情况是,作为int 传递的-127 的位模式被解释为unsigned 的位模式并导致"ffffff81"

printf("%02x \n",pop1);

为避免实现定义的行为和 UB,建议如下。对于有效的无符号代码,清楚地使用无符号类型、对象和常量。

unsigned char pop1 = len & 0xffu;
// or
uint8_t pop1 = len & 0xffu;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 2019-06-27
    • 2022-01-03
    • 1970-01-01
    • 2014-11-04
    • 2011-01-05
    • 1970-01-01
    • 2016-06-15
    相关资源
    最近更新 更多