调用vprintf()

时间:2016-11-19 05:39:46

标签: c macos printf variadic-functions

此代码有什么问题?

#include <stdio.h>
#include <stdarg.h>

void myprintf(const char * format, ...) __printflike(1, 2);

int main(int argc, const char * argv[]) {
    printf("%s\n");
    myprintf("%s\n");
    return 0;
}

void myprintf(const char * format, ...) {
    if (format) {
        va_list arguments;
        va_start(arguments, format);
        vprintf(format, arguments);
        va_end(arguments);
    }
}

使用__printflike我收到了一个很好的警告,例如printf。但与至少打印垃圾的printf不同,我在调用vprintf时获得了EXC_BAD_ACCESS,如下所示:

enter image description here

有什么方法可以让我的工作吗? 谢谢!

更新:据我所知,通过使用错误数量的参数调用函数,我得到了未定义的行为,但我希望myprintf的行为与printf一样(没有崩溃)。那可能吗?有没有办法在调用vprintf之前检查参数以避免异常?

更新2:我想我现在知道了,感谢所有的评论和答案。对于这个非常简单的例子,我认为最好使用一个宏,快速失败并在调用点崩溃:

enter image description here

3 个答案:

答案 0 :(得分:1)

Undefined意味着不可预测。在一次运行中,printf可能会产生垃圾,而在另一次运行中,它可能会产生EXC_BAD_ACCESS。您无法重现undefined behavior。在这种特殊情况下,格式化字符串中的%s术语表示printf需要查找C字符串。根据您的libc实现,当您未指定第二个参数时,它可能会在某处找到它。如果发现在距离此指针不远的地方发现了一个空字符,则会得到垃圾输出。如果没有,printf将继续搜索字符串的结尾,直到它超出分配给您的程序的内存范围,然后获得EXC_BAD_ACCESS

答案 1 :(得分:0)

不可能 - 至少不是以可移植的方式 - 确定传递给函数的参数数量。格式说明符是printf确定从堆栈中弹出多少个值的唯一方法,因此输入错误的格式说明符会为您提供未定义的行为。这只是你需要学习然后继续学习的C之一。

通过尝试&#34;纠正&#34;像这样的事情你可能只是让代码更难以理解,而其他人也难以理解。

答案 2 :(得分:0)

  

在调用vprintf以避免异常之前,有什么方法可以检查参数吗?

只需一个:认真对待编译器的警告并消除警告指向您的编程错误。

请参阅:现在它变得越来越冬天​​,街道上会有泥雪(至少在欧洲),所以你可以选择冬季轮胎安装保时捷。回到这辆漂亮的汽车后,你会在仪表板上找到以下贴纸(放在车库旁边):

enter image description here

(apx 100英里/小时)

这个贴纸提醒您,新装的冬季轮胎 支持汽车的最高速度。

你现在不能开得更快,现在期待汽车在轮胎即将破裂的那一刻停下来,不是吗?

由您决定,尊重此警告的司机!

- )