我写了一个名为Mathtext的程序。该程序通过将某些字符范围转换为Unicode范围(例如“数学字母符号”)来生成纯文本斜体,粗体,衬线等,从而提供纯文本“样式”。
它作为逐行解释器,就像一个shell,在输入一行后输出翻译的行。这意味着文件可以cat
/管道传输以翻译整个文件,以及您可以通过按^ D'退出''shell'这一事实,这可以通过stdin命中EOF来检测。
一切正常。但是,当我按^ D并退出时,它会发生段错误。我仍然无法理解造成这种情况的原因。
使用-g -O0
进行编译会有所帮助;我现在知道问题来自于按下^ D时转置中的strlen调用。但是,在^ D期间永远不应该调用转置,因为eof是真的!
Program received signal SIGSEGV, Segmentation fault. __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:31 31 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory. in ../sysdeps/x86_64/multiarch/../strlen.S (gdb) where #0 __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:31 #1 0x0000000000400b0e in transpose (s=0x0, capsDelta=120263, smallDelta=120257, numDelta=0) at mathtext.c:58 #2 0x0000000000400e2b in main (argc=2, argv=0x7fffffffe4b8) at mathtext.c:92
答案 0 :(得分:3)
你的程序取消引用NULL,因为fgets
在错误或EOF时返回NULL,并且你将它直接传递给transpose,它会天真地使用结果。
答案 1 :(得分:3)
feof()
的大多数用法都是错误 - 这个程序在这个主循环中完美地展示了它:
char temp[1048576];
do {
if (!strcmp(argv[1], "serifb"))
transpose(fgets(temp, 1048576, stdin), 119808 - 'A', 119834 - 'a', 120782 - '0');
else if (!strcmp(argv[1], "serifi"))
transpose(fgets(temp, 1048576, stdin), 119860 - 'A', 119886 - 'a', 0);
else if (!strcmp(argv[1], "serifbi"))
transpose(fgets(temp, 1048576, stdin), 119912 - 'A', 119938 - 'a', 0);
else if (!strcmp(argv[1], "sans"))
transpose(fgets(temp, 1048576, stdin), 120224 - 'A', 120250 - 'a', 120802 - '0');
else if (!strcmp(argv[1], "sansb"))
transpose(fgets(temp, 1048576, stdin), 120276 - 'A', 120302 - 'a', 120812 - '0');
else if (!strcmp(argv[1], "sansi"))
transpose(fgets(temp, 1048576, stdin), 120328 - 'A', 120354 - 'a', 0);
else if (!strcmp(argv[1], "sansbi"))
transpose(fgets(temp, 1048576, stdin), 120380 - 'A', 120406 - 'a', 0);
else if (!strcmp(argv[1], "mono"))
transpose(fgets(temp, 1048576, stdin), 120432 - 'A', 120458 - 'a', 120822 - '0');
else if (!strcmp(argv[1], "fullwidth"))
transposeBlock(fgets(temp, 1048576, stdin), '!', '~', 65281 - '!');
else return help();
} while(!feof(stdin));
在文件结束时,fgets()
将返回NULL
,然后feof()
的下一次调用将返回true。所以正确的方法是测试输入函数的返回值 - 因为无论如何你都在进行测试,所以不需要调用feof()
(除非你想区分文件错误和文件结尾) )。
char temp[1048576];
while (fgets(temp, sizeof temp, stdin) != NULL) {
if (!strcmp(argv[1], "serifb"))
transpose(temp, 119808 - 'A', 119834 - 'a', 120782 - '0');
else if (!strcmp(argv[1], "serifi"))
transpose(temp, 119860 - 'A', 119886 - 'a', 0);
else if (!strcmp(argv[1], "serifbi"))
transpose(temp, 119912 - 'A', 119938 - 'a', 0);
else if (!strcmp(argv[1], "sans"))
transpose(temp, 120224 - 'A', 120250 - 'a', 120802 - '0');
else if (!strcmp(argv[1], "sansb"))
transpose(temp, 120276 - 'A', 120302 - 'a', 120812 - '0');
else if (!strcmp(argv[1], "sansi"))
transpose(temp, 120328 - 'A', 120354 - 'a', 0);
else if (!strcmp(argv[1], "sansbi"))
transpose(temp, 120380 - 'A', 120406 - 'a', 0);
else if (!strcmp(argv[1], "mono"))
transpose(temp, 120432 - 'A', 120458 - 'a', 120822 - '0');
else if (!strcmp(argv[1], "fullwidth"))
transposeBlock(temp, '!', '~', 65281 - '!');
else return help();
}
答案 2 :(得分:1)
feof
无法预测未来。在您实际按下^ D键之前,它不知道它是文件的结尾,此时您的程序正在等待fgets
中的输入。读取文件不会产生错误,因为所有输入都已存在于开头。在转置函数中检查NULL。