fprintf 调用抛出 EXC_BAD_ACCESS 异常
The fprintf call throws EXC_BAD_ACCESS exception
当我 运行 在我的 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]='[=11=]';
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]='[=11=]';
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
最后一个堆栈帧是这样的:我认为文件锁似乎有问题。
如评论中所述,您将缓冲区 buf
传递给 fprintf()
而不是 FILE
指针 fp
,这会导致 UB。
当您尝试执行类似启用警告标志的操作时,每个合理的编译器都会打印警告。当您启用所有编译器警告时,您可以避免大量调试,并且仅当您确定不希望对某种类型的错误发出警告时才禁用特定警告。
如此处 所述,您可以通过将编译器标志添加到 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
当我 运行 在我的 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]='[=11=]';
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]='[=11=]';
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
最后一个堆栈帧是这样的:我认为文件锁似乎有问题。
如评论中所述,您将缓冲区 buf
传递给 fprintf()
而不是 FILE
指针 fp
,这会导致 UB。
当您尝试执行类似启用警告标志的操作时,每个合理的编译器都会打印警告。当您启用所有编译器警告时,您可以避免大量调试,并且仅当您确定不希望对某种类型的错误发出警告时才禁用特定警告。
如此处 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