【问题标题】:Printf %X identifier - Weird behaviour with pointersPrintf %X 标识符 - 带有指针的奇怪行为
【发布时间】:2014-02-13 15:54:49
【问题描述】:

我最近在接受采访,被问到一个问题:


看看这段代码,写出它的输出:

unsigned char buff[] = { 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33 };
unsigned long *pD = (unsigned long *)buff;
unsigned short *pS = (unsigned short *)buff;
void *pEnd = &buff[sizeof(buff) - 1];

for (; pD < pEnd; pD++)
    printf("0x%X\n", *pD);

for (; pS < pEnd; pS++)
    printf("0x%X\n", *pS);

return 0;

现在假设系统是32bits,unsigned long是4个字节,答案是:

  • 0x11111111
  • 0x22222222
  • 0x33333333
  • 0x1111
  • 0x1111
  • 0x2222
  • 0x2222
  • 0x3333
  • 0x3333

现在我的问题:

为什么它只用 unsigned short 变量打印 16 位? 我知道 unsigned short 是 2 个字节,但 printf 知道根据 %X 从堆栈中解析多少字节,读取为 unsigned int。我假设它会一直读取 4 个字节(无符号整数),有时会出现垃圾(或最终损坏的堆栈)。

你怎么看?

谢谢!

【问题讨论】:

  • 请注意,从技术上讲,将unsigned long 传递给"%X" 说明符是未定义的行为。它可以在大多数 32 位系统上工作(尽管人们可以很容易地想象一种实现方式它没有),但会在大多数 64 位系统上导致问题。
  • 而在面试中问这个问题的人显然不是很能干。
  • unsigned long *pD = (unsigned long *)buff; 可能会遇到对齐问题,并可能在各种平台上失败。 unsigned short *pS = ... 也。
  • @James Kanze unsigned long"%X" 说明符也会在 sizeof(int) &lt; sizeof(long) 与 16 位 int 和 32 位 long 一样失败,这在 2014 年的嵌入式系统中很常见。
  • @chux 是的。我刚刚提到了普通用户最常见的情况。

标签: c++ c printf


【解决方案1】:

*pS 是 unsigned short 类型,因此使用此值。尽管 printf 期望 %X 是 int,但您提供了一个 unsigned short,它被提升为 int。所以顺序是:从数组中读取前 2 个字节,因为 *pS 是无符号短的。然后这个 unsigned short 值被提升为 int。

【讨论】:

    【解决方案2】:

    输出中没有指针。通过取消引用,您告诉 printf 输出一个简短的内容,这就是它的作用。 %X 仅将其显示为十六进制。

    【讨论】:

    • printf 不知道你传递的是什么类型。传递错误的类型是未定义的行为(但在unsigned short 的情况下,会发生整数提升,因此类型是正确的)。
    猜你喜欢
    • 1970-01-01
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    相关资源
    最近更新 更多