【问题标题】:Printf() printing of arguments and pointers in CPrintf() 在 C 中打印参数和指针
【发布时间】:2015-08-29 17:46:27
【问题描述】:

好的,所以基本上我正在尝试使用 printf 和各种形式的指针来了解这里发生了什么

这是代码

#include <stdio.h>
#include <stdlib.h>

typedef struct mine{
   unsigned int  memory;
   struct mine * next;
}mine;


int main(int argc, char *argv[]){

   mine * y;

   y = (struct mine *)malloc(sizeof(struct mine));
   y->memory = 0xBEEFDEAD;

   printf("%x\n",*y);
   printf("%x\n",y[0]);
   printf("%x\n",y->memory);
   printf("%x %x %x\n",y->memory, *y,y[0]);

   return 0;
}

这是输出

beefdead
beefdead
beefdead
beefdead beefdead 7c00c0

正如您所见,打印的相同指针在单独分开和组合在一起时,使用 printf 给出不同的结果

这是我打印指针方式的问题,还是 printf 的问题

*y = y[0] = y->内存也是如此

从输出中我不确定这个问题的答案

【问题讨论】:

  • 请使用 C bokk 或使用不同的。您在这里做错了太多,表明您确实需要首先正确掌握基础知识。您的代码甚至无法编译。
  • 标准警告:不要将malloc 和朋友的结果投射到 C 中!
  • @hopjoppe5 你的问题还不清楚。我们无法读懂你的想法;我们只能分析您在此处发布的代码。您在此处发布的内容充满了错误;没有办法解释你可能或可能从你的真实代码中得到的任何输出,只有你能看到。
  • @hopjoppe5 指出代码中的错误是本网站的目的(除其他外)。这不是对您的代码的“攻击”。这也不是对的攻击;你不是你的代码。
  • 听着,我不想在这里为@Olaf 辩护,只是因为他是社区中的一员,享有一定的声誉(顺便说一句,这来自于实际帮助人们),但我必须在阅读了您的其他一些“问题”后承认您非常擅长与试图帮助您的人打架。这是一个很好的例子 - stackoverflow.com/a/32218272/2016408

标签: c pointers printf


【解决方案1】:

这是我打印指针的方式有问题吗

代码从不尝试打印指针。代码尝试打印*yy[0]y-&gt;memory。这些是minemineunsigned 类型。

要打印像 y 这样的指针,请使用 printf 说明符 "%p" 并在指针尚未准备好时转换为 (void *) void *

printf("%p\n", (void *) y);

要打印struct mine 等结构的内容,请打印各个子字段。见下文。

与传递的扩充不匹配的打印格式说明符会导致 C 规范指定的行为为未定义的行为。结果可能是什么?对此类行为的任何解释都依赖于有关底层生成代码的许多假设,坦率地说,这是很多猜测工作。

将匹配的printf() 格式说明符与匹配类型的值一起使用。

许多编译器会警告此类不匹配。确保您的编译器的警告完全启用。节省您的时间。


"%x" 匹配 unsigned,而不是类型 mine。结果:未定义的行为。

mine * y;
...
// printf("%x\n", *y);
// Instead:
printf("%x %p\n", y->memory, (void *) y->next);

printf("%x\n", y[0]); 相同结果:未定义的行为。

// printf("%x\n", y[0]);
// Instead:
printf("%x %p\n", y[0].memory, (void *) y[0].next);

printf("%x\n", y[0]); 相同结果:未定义的行为。

// printf("%x %x %x\n", y->memory, *y, y[0]);

【讨论】:

    【解决方案2】:

    当你这样做时:

    printf("%x\n",*y);
    

    或者这个:

    printf("%x\n",y[0]);
    

    您将 struct mine 提供给 %x 格式说明符。这是未定义的行为,这意味着任何事情都可能发生。

    在特定机器上的特定编译器的情况下,%x 说明符可能会拾取正在传递的struct mine 的前 4 个字节,其中恰好是 memory 的内容。但是你不能依赖这种行为。如果您使用不同的编译器甚至在不同的机器上运行相同的可执行文件,它可能会做一些不同的事情。

    在这一行的情况下:

    printf("%x %x %x\n",y->memory, *y,y[0]);
    

    第一个参数很好,总是会打印出你所期望的。如前所述,第二个参数调用未定义的行为。在带有特定编译器的特定机器上,它会为第二个 %x 打印 memory 的内容,如前面的示例所示。对于第三个%x,它会在堆栈中查找接下来的 4 个字节。这不是您传入的y[0],而是传入*ynext 的内容,因为为包含8 个字节的第二个参数传递了struct mine

    但同样,这种行为是未定义的。如果您使用不同的编译器、更改编译器设置或在不同的机器上运行,它可能会打印出完全不同的东西。无法保证发生在你身上的事情总会发生。

    这不是您在 cmets 中建议的 printf 的问题。这是你在调用未定义的行为。

    编辑:

    如果您尝试查看y-&gt;memory*yy[0]地址,则需要传递每个地址并使用%p 格式正确输出它们的说明符:

    printf("%p %p %p\n", (void *)&y->memory, (void *)y, (void *)&y[0]);
    

    由于y[0] 等价于*(y + 0)(即*y),并且因为memory 是结构的第一个字段,所以这将输出三个相同的(系统相关的)值。

    【讨论】:

    • 嗨,感谢您的时间和回答,如果我单独使用这些命令怎么办? *x 或 x[0] 或 x->memory 是否正常且不会导致未定义的行为?如上面的示例中包含所有这些的 printf 行?
    • 不,由于我指定的原因,单独使用它们仍然是未定义的行为。仅仅因为它碰巧打印出你所期望的并不意味着行为是明确定义的。
    • @hopjoppe5 这能回答你的问题吗?
    • 不,它没有,因为你说被执行的代码是由处理这个问题的编译器随机生成的?
    • 生成的代码不是随机的,但是代码的行为基本上是如果您使用了不正确的格式说明符,即读取您不应该的内存。我做了一个编辑,解决了我认为你正在努力完成的事情。
    猜你喜欢
    • 1970-01-01
    • 2012-10-29
    • 2023-03-12
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多