堆栈对格式字符串的作用

the stack's role with format strings

好的,这会有点冗长。

所以我有一个程序在 printf() 语句中使用两个 %n 格式参数。 %n本质上是写数据,什么都不显示... 所以当我的格式化函数遇到%n参数时,它会将函数已经写入的字节数写入相应函数参数的地址。


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

 int main() {

 int A = 5, B = 7, count_one, count_two;

 printf("The number of bytes written up to this point X%n is being stored in
 count_one, and the number of bytes up to here X%n is being stored in
 count_two.\n", &count_one, &count_two);

 printf("count_one: %d\n", count_one);
 printf("count_two: %d\n", count_two);

 printf("A is %d and is at %08x. B is %x.\n", A, &A, B);

 exit(0); 
 } 

程序的输出是:

The number of bytes written up to this point X is being stored in count_one,and the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at bffff7f4. B is 7.

关于这个printf

printf("A is %d and is at %08x. B is %x.\n", A, &A, B);

现在,参数以相反的顺序入栈,先是B的值,然后是A的值地址,然后是A的值地址,最后是格式字符串的地址...

现在,如果使用三个格式参数的格式字符串仅将两个参数压入堆栈?

所以我删除了上面代码中的最后一个参数以匹配此 printf() 参数

printf("A is %d and is at %08x. B is %x.\n", A, &A);

我编译和执行时发生的事情是...

The number of bytes written up to this point X is being stored in count_one, and the number of
bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at bffffc24. B is b7fd6ff4

所以我得到这个 b7fd6ff4,那是什么?这与格式函数的堆栈帧的关系意味着什么?

任何见解或解释将不胜感激。

格式说明符数量错误或格式说明符不匹配调用 undefined behavior

来自 C standard 关于 fprintf 函数的第 7.21.6.1 节:

9 If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

这意味着如果您没有向函数传递足够的参数,您将无法对函数将接收到的值做出任何可靠的预测。在使用堆栈并禁用优化的实现中最有可能发生的是,它将获取内存中恰好位于最后一个压入堆栈的参数旁边的任何值。

在 32 位 x86 调用约定下,所有函数参数都在堆栈上传递。如果您使用比参数更多的格式说明符调用 printf(),该函数将很乐意继续向上移动堆栈并获取任何值以找到要显示的内容。

堆栈的具体内容将是变量——通常是函数局部变量、函数return指针或堆栈指针。

printf 假定您已将所有 4 个参数压入堆栈。无论您是否提供,它都期望 B 在堆栈上。如果您没有提供它,那么它将使用该内存位置中的任何内容并打印出来。

以下建议代码:

  1. 修复问题评论中列出的问题
  2. 干净地编译
  3. 执行所需的功能

现在建议的代码:

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

int main( void )
{
    int A = 5;
    int B = 7;
    int count_one;
    int count_two;

    printf("The number of bytes written up to this point X%n is being stored"
        " in count_one, and the number of bytes up to here X%n is being"
        " stored in count_two.\n",
        &count_one,
        &count_two);

    printf("count_one: %d\n", count_one);
    printf("count_two: %d\n", count_two);

    printf("A is %d and is at %p. B is %x.\n", A, (void*)&A, B);

    exit(0);
}

程序的典型 运行 结果是:

The number of bytes written up to this point X is being stored in count_one, and the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at 0x7fff19c28ea8. B is 7.