【问题标题】:The fprintf call throws EXC_BAD_ACCESS exceptionfprintf 调用引发 EXC_BAD_ACCESS 异常
【发布时间】:2021-01-05 06:32:24
【问题描述】:

当我在我的 Mac 上运行如下所示的 APUE 示例代码时,它会引发 EXC_BAD_ACCESS 异常。我检查了文件光标,它位于正确的位置 12。我什至尝试用fputc 替换fprintf。之后,它工作正常并且异常消失了。但我想知道外面发生了什么以及为什么。

#include "apue.h"

#define BSZ 48

int main(){
  FILE *fp;
  char buf[BSZ];

  memset(buf,'a',BSZ-2);
  buf[BSZ-2]='\0';
  buf[BSZ-1]='X';
  if ((fp = fmemopen(buf,BSZ,"w+")) == NULL)
      err_sys("fmemopen failed");
  printf("initial buffer contents: %s\n",buf);
  fprintf(fp, "hello, world");
  printf("before flush: %s\n", buf);
  fflush(fp);
  printf("after fflush: %s\n",buf);
  printf("len of string in buf = %ld\n",(long)strlen(buf));

  memset(buf,'b', BSZ-2);
  buf[BSZ-2]='\0';
  buf[BSZ-1]='X';
  fprintf(buf, "hello, world");
//  fputc('a',fp);
  fseek(fp,0,SEEK_SET);
  printf("after fseek: %s\n",buf);
  printf("len of string in buf = %ld\n", (long)strlen(buf));
}

控制台输出如下:

/Users/heping/Documents/APUE-Example-Code/stdio/cmake-build-debug/memstr
initial buffer contents: 
before flush: hello, world
after fflush: hello, world
len of string in buf = 12
Exception: EXC_BAD_ACCESS (code=1, address=0x8)

Process finished with exit code 9

最后一个堆栈帧是这样的:我认为文件锁定似乎有问题。

【问题讨论】:

  • 嗨,有趣,大概是 BSZ 的大小?
  • @IronMan 我不这么认为,因为缓冲区有 48 字节大,文件光标位于 12 字节位置。我想写的字符串是12字节长,所以写操作后的总长度不会超过48字节长。正确的?更重要的是,如果我用 fputc 替换 fprintf,一切都很有趣。 :)
  • 您在fprintf 语句中不小心将char buf[48]; 作为FILE* 参数传递了。这就是它崩溃的原因。因为我使用了-Werror,所以我的编译器阻止了我执行程序。
  • @Neal.Marlin: (a) 除了err_sys 函数之外,它不是整个程序。它缺少BSZ 的定义并包含多个标头。 (b) 由于缺少err_sys,因此它不是minimal reproducible example。提供完整可重现示例的一个原因是,其他人可以轻松地运行该程序以进行自己的测试和调试。仅仅声称缺少的部分是什么是不够的。询问时,您应该提供 everything 或重写示例以不需要您省略的部分。遵循指南并帮助人们帮助您。

标签: c macos io posix


【解决方案1】:

正如在 cmets 中已经讨论的那样,您将缓冲区 buf 传递给 fprintf() 而不是 FILE 指针 fp,这会导致 UB。

当您尝试执行启用警告标志的类似操作时,每个合理的编译器都会打印警告。当您启用所有编译器警告时,您可以避免大量调试,并且仅在您确定不希望针对某种类型的错误发出警告时才禁用特定警告。 如How to enable all compiler warnings in CLion? 所述,您可以通过将编译器标志添加到CMakeLists.txt 来启用警告。对于 C 代码的所有警告,添加以下行:

set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Werror")

-Wall 将启用所有正常警告,-Wextra 将启用附加警告,-Wpedantic 将警告不严格遵循您指定的 C 标准,-Werror 将把每个警告都变成错误,所以你必须在编译程序之前修复错误。如果您收到不想要的警告,您可以用同样的方式禁用它们,如下所示:

set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Werror -Wno-cast-function-type")

-Wno-cast-function-type 将禁用有关将函数指针转换为不同函数指针的警告。您可以阅读所有警告选项here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-28
    • 2020-11-07
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多