【问题标题】:EXC_BAD_ACCESS when calling vprintf()调用 vprintf() 时的 EXC_BAD_ACCESS
【发布时间】:2017-04-03 01:04:09
【问题描述】:

这段代码有什么问题?

#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,如下所示:

有什么方法可以让我完成这项工作吗? 谢谢!

更新: 我知道通过使用错误数量的参数调用函数,我会得到未定义的行为,但我希望 myprintf 的行为就像 printf 一样(不会崩溃) .那可能吗?有什么方法可以在调用vprintf 之前检查参数以避免异常?

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

【问题讨论】:

  • "printf,至少打印垃圾"。这不是保证的行为。当您故意将具有未定义行为的错误放入代码中时,您不能期望它“至少打印垃圾”。 UB 表示行为不可预测。它可以立即崩溃,它可以稍后崩溃,它可以打印垃圾,它不能打印任何东西,......
  • @kaylum 我更新了我的问题,因为我想知道我的函数是否可以以未定义的方式表现得像printf。从您的角度来看......如果调用者传递错误的参数,记录该行为是未定义的就足够了吗?谢谢!
  • 程序崩溃比继续运行要好得多。你需要你的程序崩溃。这是错误的。如果它崩溃了,它不会再造成任何伤害。如果它继续下去,谁知道它会造成什么损害。你正在寻找一个毫无意义和不受欢迎的目标——而且是一个无法实现的目标,因为你不能强迫未定义的行为以任何特定的方式表现。另见Fail Fast

标签: c macos printf variadic-functions


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    通过尝试“纠正”这样的事情,您可能只会使代码更难读,其他人也难以理解。

    【讨论】:

      【解决方案3】:

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

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

      请看:现在进入冬天了,街道上会出现泥泞和雪(至少在欧洲),所以您可以在自己喜欢的车库中将冬季轮胎安装到您的保时捷上。归还这辆好车时,您会在仪表板上找到以下贴纸(贴在车库旁边):

      (大约 100 英里/小时)

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

      如果你希望汽车在轮胎即将破裂的那一刻停下来,你不会开得更快,不是吗?

      这取决于你,司机是否尊重这个警告!

      ;-)

      【讨论】:

        猜你喜欢
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多