C printf的输出是什么(“d”、“Hello”x2B;1);?

C printf的输出是什么(“d”、“Hello”x2B;1);?,c,C,我正在运行一个c程序,其中包含以下语句: #include <stdio.h> #include <string.h> main() { printf("%d","Hello"+1); } #包括 #包括 main(){ printf(“%d”、“Hello”+1); } 它将4196445作为输出。是否正确..请解释逻辑这将打印 (字符串地址(“Hello”)+1) 所以,在您的例子中,字符串“Hello”的基址是4196444。 这就是输出打印为41964

我正在运行一个c程序,其中包含以下语句:

#include <stdio.h>
#include <string.h>
main() {
  printf("%d","Hello"+1);  
}
#包括
#包括
main(){
printf(“%d”、“Hello”+1);
}

它将4196445作为输出。是否正确..请解释逻辑

这将打印 (字符串地址(“Hello”)+1)

所以,在您的例子中,字符串“Hello”的基址是4196444。 这就是输出打印为4196445的原因

printf(“%d”,“Hello”+1)”的输出是什么

其他人则声称它将“打印字符串地址加1”。这可能是真的,也可能不是真的。原因是您的代码调用了未定义的行为,因为您正在打印类型为
char*
的对象,该对象的格式说明符仅适用于
int

因此,编译器和随后的代码可以随心所欲地执行任何操作(包括擦除硬盘或下载最新的Justin Bieber专辑)。

尽管有人会说“根据标准,这是未定义的行为”,但事实上会发生以下情况。请注意,这是一个非常笼统的描述,根据您的平台(编译器、CPU体系结构、操作系统、MMU、标准输出控制器等)可能略有不同:

  • 编译器生成一个以null结尾的字符串(
    “Hello”
    ),并将其放置在程序的代码部分(更准确地说是RO数据部分)

  • 每次创建进程并将可执行映像加载到内存中(即,每当运行程序时),都会出现一个包含字符的字符串
    'H'
    'e'
    'l'
    'l'
    'o'
    '\0'
    驻留在逻辑内存地址4196444处。该字符串的物理内存地址可以通过将该值添加到基址寄存器的值来计算(尽管这与您无关,因为您的程序不知道)

  • 由于此字符串的逻辑地址在每次执行程序时将保持4196445,因此编译器可以将
    “Hello”+1
    的计算替换为常量值4196445

  • 因此您可以想象,编译器没有编译
    printf(“%d”,“Hello”+1)
    ,而是编译
    printf(“%d”,4196445)
    。事实上,由于
    “%d”
    字符串也是位于程序代码部分的常量字符串,因此它也被一些常量值替换

  • 顺便说一句,如果您使用的变量指向
    “Hello”
    字符串,那么编译器在编译过程中无法确定该值,将生成代码在运行时进行计算。计算本身将使用堆栈或通用寄存器(或两者的组合)执行。下面是如何通过堆栈计算此值的典型示例(堆栈是程序的另一部分,与代码部分类似,但具有写入权限):

    • 变量的值被推入堆栈

    • 值1被推入堆栈中

    • 前两个元素从堆栈中弹出并添加

    • 结果被推回堆栈

  • 在任何情况下,当调用
    printf(“%d”,“Hello”+1)
    时:

    • 字符串
      “%d”
      的地址被推入堆栈

    • 字符串
      “Hello”
      加1的地址被推入堆栈

    • 程序计数器(或有人称之为指令指针)跳转到内存中函数
      printf
      的地址,并从那里继续执行

    • 对于传递给函数
      printf
      的第一个参数所指向的字符串中的每个
      %
      字符,函数从堆栈中加载相应的参数,然后根据
      %
      字符后指定的类型计算要打印的数据

    • 最后,结果被发送到屏幕(更准确地说,对于结果中的每个字符,生成一个标准输出中断,导致PC(程序计数器)/IP(指令指针)跳转到IV(中断向量),其中指定的ISR(中断服务例程),它本质上是一个函数,与代码中的任何其他函数一样,被调用,然后将输入字符写入标准输出控制器的FIFO队列)


正如@hvd在以下评论中所暗示的:


在64位系统上,
%d%
会将
“Hello”+1
的结果从64位值截断为32位值。使用
%lld
可以解决这个问题,但当然-正确的解决方案是使用
%p

为什么要这样做?这不是定义好的行为,即使定义好了也没有多大意义。你想做什么?不确定它是否是未定义的行为,但发生的是
“Hello”
const char*
+1
使其成为
int
,因此它正在打印文本字符串的地址
“Hello”
plusone@BryanChen:向指针添加1不会使其成为int。它是指针算法;结果仍然是指针。@BryanChen:指针加上整数在C中仍然是指针。指针作为原始数据传递给变量函数,但随后该函数将其解释为int。我认为对格式说明符使用错误的数据类型是未定义的行为。(因此标准委员会是稳妥的。)指针的大小不一定是int。很可能
4196445
甚至不是正确的地址。谁投了反对票,为什么?问题和建议