【问题标题】:C - Printing negative int values as hex produces too many charactersC - 将负整数值打印为十六进制会产生太多字符
【发布时间】:2015-05-21 15:50:53
【问题描述】:

在 CentOS-5 64 位上使用 gcc 4.1.2 编译。

将整数打印为两个字符的十六进制字符串:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
   int8_t iNegVar = -1;
   int8_t iPosVar =  1;

   printf(" int negative var is <%02X>\n", iNegVar);
   printf(" int positive var is <%02X>\n", iPosVar);

   return 0;
}

由于该值只有 1 个字节,我希望整数值“-1”会打印“0xFF”。但是,我得到:

 int negative var is <FFFFFFFF>
 int positive var is <01>

我尝试将其抽象为 char* 缓冲区,以一次打印 1 个字节。这产生了相同的结果:

#include <stdio.h>
#include <stdint.h>

void print_hex(void* pBuffer, uint8_t uiBufSize);
int main(void)
{
   int8_t iNegVar = -1;
   int8_t iPosVar =  1;

   printf(" int negative var is <%02X>\n", iNegVar);
   print_hex(&iNegVar, 1);                               //pass by reference 


   printf(" int positive var is <%02X>\n", iPosVar);
   print_hex(&iPosVar, 1);                               //pass by reference

   return 0;
}


void print_hex(void* pBuffer, uint8_t uiBufSize)
{
   int i;
   char pTmp[3];                                 //Holds 2-character string, plus NULL
   char* pByteBuff = pBuffer;                    //Use char* to parse byte-by-byte

   for(i = 0; i < uiBufSize; i++)                //Process all bytes in buffer
   {
      sprintf(pTmp, "%02X", pByteBuff[i]);       //store each byte as 2-character string in "pTmp"
      printf(" Converted to %s!\n\n", pTmp);
   }
}

打印:

int negative var is <FFFFFFFF>
Converted to FFFFFFFF!

int positive var is <01>
Converted to 01!

我认为“char”在 C 中是作为整数类型实现的,所以我决定尝试在“print_hex”函数中将“char* pByteBuff”更改为“unsigned char* pByteBuff” .这行得通,并且只打印了我期望的两个字符:

int negative var is <FFFFFFFF>
Converted to FF!

虽然这“解决”了我的问题,但问题仍然存在:为什么显式打印为两个字符的十六进制值会打印 8 个字符而不是指定的两个字符?

【问题讨论】:

  • 这是因为负数的二进制表示:en.wikipedia.org/wiki/Signed_number_representations
  • @iharob - 我试了一下,并在原始问题发布中提到了它。它有效——寻找更多的“为什么”。感谢您的评论。
  • 注意:""int8_t" 可能只有 1 个字节,也可能不只有 1 个字节" - 我确信如果系统支持 int8_t,它是可选的,它必须是 1 个 char (字节)在 大小.
  • @guidotex 规范“c11 der 7.20.1.1 精确宽度整数类型”确实详细说明了精确宽度类型,例如int8_t,因为它是 2 的补码并且没有填充:正好是 8 位“因此,@987654330 @ 表示这种有符号整数类型,宽度正好为 8 位。” - 除了更广泛的精确类型的字节序和对齐要求外,没有编译器回旋余地。 unsigned char 不允许有填充 & char 必须是最小尺寸类型且至少 8 位:尔格 char 是 8 位。
  • @guidotex ...“当 sizeof 应用于类型为 char、unsigned char 或 signed char 的操作数(或其合格版本)时,结果为 1”§6.5.3.4 4

标签: c


【解决方案1】:

int8_t 将通过通常的整数提升作为参数传递给像printf() 这样的可变参数函数。这通常意味着int8_t 被转换为int

然而"%X" 是用于unsigned 参数的。所以首先隐蔽到一些无符号类型并使用匹配的格式说明符:

对于uint8_t,使用PRIX8。对于精确宽度类型,包括 &lt;inttypes.h&gt; 以作为匹配说明符。

#include <inttypes.h>
printf(" int negative var is <%02" PRIX8 ">\n", iNegVar);`

使用int8_t iNegVar = -1;,在以十六进制打印之前转换为某种无符号类型

printf(" int negative var is <%02" PRIX8 ">\n", (uint8_t) iNegVar);`

【讨论】:

  • 我没想过要使用精确宽度类型的宏和演员表。不知道 %X 用于无符号参数 - 只是认为它采用了参数的任何位值。谢谢!
  • @guidotex 确实,大多数 系统可以很好地与"%x" 一起工作,并且传递了一些有符号整数——但它是符合规范的 UB。
【解决方案2】:

这是因为 %x 的默认大小为 int。
如果你想要字符,请使用%hhx
或者更好的是,你有macros in &lt;cinttypes&gt;,比如PRIx8

【讨论】:

  • 这行得通,让我开始思考正确的方向。谢谢。
【解决方案3】:

当您将 char 值传递给 sprintf() 或任何其他可变参数 C 函数时,在这种情况下,它会提升为 int 值 -1。现在你通过“%X”规范将它打印为unsigned int,所以你用FF得到长号。另一侧的unsigned char 提升为unsigned int,所以你得到0xFF 整数值,它被打印为2 个符号。

注意:您在printf() 格式中指定 %X - unsigned int 的事实只会影响 printf 函数如何处理传递给它的值。 Char -> int 提升发生在调用 printf() 之前,格式说明符没有效果,只有您传递的值的类型。

【讨论】:

  • 应该明确的是,在-1 上使用%X 会导致未定义的行为
猜你喜欢
  • 2011-04-19
  • 2015-12-16
  • 2015-02-14
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2014-09-18
  • 1970-01-01
  • 2013-12-13
相关资源
最近更新 更多