堆栈的格式字符串角色

问题描述 投票:0回答:4

好的,这有点冗长。

所以我有一个程序,它使用两个%n格式参数,这是一个printf()语句。 %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是%d,位于%08x。B是%x。\ n”,A,&A,B);

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

现在,如果只有两个参数被推送到堆栈,其格式字符串使用三个格式参数?

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

printf(“A是%d,位于%08x。B是%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,那是什么?这与格式函数的堆栈帧的关系意味着什么?

任何见解或解释都将非常感激。

c parameters stack printf format-string
4个回答
2
投票

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

关于C standard功能的fprintf第7.21.6.1节:

9如果转换规范无效,则行为未定义.282)如果任何参数不是相应转换规范的正确类型,则行为未定义。

这意味着如果你没有传递足够的参数,你就无法对函数将获得的值进行任何可靠的预测。在使用堆栈并禁用优化的实现中最有可能发生的事情是,它将获取在推入堆栈的最后一个参数旁边的内存中接下来发生的任何值。


1
投票

以下提议的代码:

  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.

0
投票

在32位x86调用约定下,所有函数参数都在堆栈上传递。如果你使用更多的格式说明符调用printf()而不是参数,函数将很乐意继续向上移动堆栈并抓住任何值来查找要显示的内容。

堆栈的具体内容将是可变的 - 通常是函数局部变量,函数返回指针或堆栈指针。


0
投票

printf假设你在堆栈上推送了所有4个参数。无论你是否提供,它都期望B在堆栈中。如果你没有提供它,那么它将使用该内存位置中的任何内容并打印它。

© www.soinside.com 2019 - 2024. All rights reserved.