当前位置:  开发笔记 > IOS > 正文

打印%d时printf的行为而不提供变量名称

如何解决《打印%d时printf的行为而不提供变量名称》经验,为你挑选了2个好方法。

我刚刚遇到一个奇怪的问题,我正在尝试printf一个整数变量,但是我忘了指定变量名,即

printf("%d");

代替

printf("%d", integerName);

令人惊讶的是程序编译,有输出,它不是随机的.事实上,它恰好是我想要首先打印的整数,恰好是m-1.

printf只要程序继续运行,错误语句就会一直输出m-1 ...换句话说,它的行为就像语句读取一样

printf("%d", m-1);

谁知道这种行为背后的原因?我在没有任何命令行选项的情况下使用g ++.

#include 
#define maxN 100
#define ON 1
#define OFF 0

using namespace std;

void clearArray(int* array, int n);
int fillArray(int* array, int m, int n);

int main()
{
    int n = -1, i, m;
    int array[maxN];
    int found;

    scanf("%d", &n);

    while(n!=0)
    {
        found=0;
        m = 1;
        while(found!=1)
        {
            if(m != 2 && m != 3 && m != 4 && m != 6 && m != 12)
            {
                clearArray(array, n);
                if(fillArray(array, m, n) == 0)
                {
                    found = 1;
                }
            }
            m++;
        }

        printf("%d\n");

        scanf("%d", &n);
    }

    return 0;
}

void clearArray(int* array, int n)
{
    for(int i = 1; i <= n; i++)
        array[i] = ON;
}

int fillArray(int* array, int m, int n)
{
    int i = 1, j, offCounter = 0, incrementCounter;

    while(offCounter != n)
    {
        if(*(array+i)==ON) 
        {
            *(array+i) = OFF;
            offCounter++;       
        }
        else 
        {
            j = 0;
            while((*array+i+j)==OFF)
            {
                j++;
            }
            *(array+i+j) = OFF;
            offCounter++;           
        }
        if(*(array+13) == OFF && offCounter != n) return 1;
        if(offCounter ==n) break;

        incrementCounter = 0;       
        while(incrementCounter != m)
        {
            i++;
            if(i > n) i = 1;
            if(*(array+i) == ON) incrementCounter++; 
        }       
    }

    return 0;
}

Mike Thompso.. 25

你说"令人惊讶的是程序编译".实际上,这并不奇怪.C&C++允许函数具有可变参数列表.printf的定义是这样的:

int printf(char*, ...);

"..."表示该函数有零个或多个可选参数.实际上,C具有可选参数的主要原因之一是支持printf&scanf系列函数.

C没有printf函数的特殊知识.在你的例子中:

printf("%d");

编译器不分析格式字符串并确定缺少整数参数.这是完全合法的C代码.您缺少参数的事实是仅在运行时出现的语义问题.printf函数将假定您已提供参数并在堆栈中查找它.它会接收发生在那里的任何事情.只是在您的特殊情况下,它正在打印正确的东西,但这是一个例外.通常,您将获得垃圾数据.这种行为因编译器而异,并且也会根据您使用的编译选项而改变; 如果你打开编译器优化,你可能会得到不同的结果.

正如我的回答中的一条评论所指出的,一些编译器具有"lint"功能,可以实际检测错误的printf/scanf调用.这涉及编译器解析格式字符串并确定预期的额外参数的数量.这是非常特殊的编译器行为,并且在一般情况下不会检测错误.即如果您编写自己的"printf_better"函数,该函数与printf具有相同的签名,则编译器将不会检测是否缺少任何参数.



1> Mike Thompso..:

你说"令人惊讶的是程序编译".实际上,这并不奇怪.C&C++允许函数具有可变参数列表.printf的定义是这样的:

int printf(char*, ...);

"..."表示该函数有零个或多个可选参数.实际上,C具有可选参数的主要原因之一是支持printf&scanf系列函数.

C没有printf函数的特殊知识.在你的例子中:

printf("%d");

编译器不分析格式字符串并确定缺少整数参数.这是完全合法的C代码.您缺少参数的事实是仅在运行时出现的语义问题.printf函数将假定您已提供参数并在堆栈中查找它.它会接收发生在那里的任何事情.只是在您的特殊情况下,它正在打印正确的东西,但这是一个例外.通常,您将获得垃圾数据.这种行为因编译器而异,并且也会根据您使用的编译选项而改变; 如果你打开编译器优化,你可能会得到不同的结果.

正如我的回答中的一条评论所指出的,一些编译器具有"lint"功能,可以实际检测错误的printf/scanf调用.这涉及编译器解析格式字符串并确定预期的额外参数的数量.这是非常特殊的编译器行为,并且在一般情况下不会检测错误.即如果您编写自己的"printf_better"函数,该函数与printf具有相同的签名,则编译器将不会检测是否缺少任何参数.


您可以告诉编译器检查参数.我们知道在这种情况下编译器是g ++,所以使用-Wformat选项,它包含在-Wall中.

2> Joe..:

看起来像这样.

printf("%d", m);

在大多数系统中,字符串的地址将被推入堆栈,然后'm'作为整数(假设它是int/short/char).没有警告,因为printf基本上被宣布为'int printf(const char *, ...);'- 意思是'任何事情都去'.

因此,"任何事情都会发生",当你把变量放在那里时会发生一些奇怪 任何小于int的整数类型都是int - 就像那样.什么都不发送也没问题.

在printf实现中(或者至少是一个'简单'实现),你会发现va_list和的使用va_arg(根据一致性,名称有时略有不同).这些是实现用于遍历参数列表的"..."部分的内容.这里的问题是没有类型检查.由于没有类型检查,printf当它查看格式字符串时会从执行堆栈中提取随机数据("%d")并认为应该是'int'下一个.

在黑暗中随机拍摄会说你在printf之前调用的函数可能'm-1'是第二个parm吗?这是许多可能性中的一种 - 但如果碰巧是这种情况,那将会很有趣.:)

祝好运.

顺便说一句 - 大多数现代编译器(我相信GCC?)都有警告可以启用以检测这个问题.我相信Lint也是如此.不幸的是,我认为使用VC你需要使用/ analyze标志而不是免费获得.

推荐阅读
虎仔球妈_459
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有