2010-08-31 42 views
4

我寫了一個叫Mathtext的程序。此程序通過將某些字符範圍轉換爲Unicode數字範圍(如「數學字母符號」)來產生純文本「樣式」,以生成明文斜體,粗體,襯線字體等。這個程序爲什麼會出現故障?

它用作逐行解釋器,就像一個shell一樣,在一行輸入後輸出翻譯後的行,這意味着文件可以被cat /管道翻譯整個文件,以及事實上你可以通過按^ D'退出'shell' ,這是由標準輸入打EOF檢測。

一切正常。但是,當我按下^ d退出,它出現segfaults。我現在還不能很好地領會是什麼原因造成這一點。

與01編譯有一點幫助;我現在知道,當^ 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

請出示各地mathtext.c – Fosco 2010-08-31 12:27:45

回答

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(); 
} 
+0

非常感謝,您的解決方案非常完美! – 2010-08-31 23:29:24

3

您的程序取消引用NULL,因爲fgets回報的錯誤或EOF空,你傳遞這直接轉它使用的結果天真。

1

feof無法預測未來。它不知道它是文件的結尾,直到您實際按下^ D鍵,此時程序正在等待輸入fgets。讀取文件不會產生錯誤,因爲所有輸入在開始時已經存在。在轉置功能中檢查NULL。

+0

更簡單的方法說這是92行代碼:EOF沒有設置直到你讀過去EOF。最後一次有效讀取將讀取UP-TO,但不能讀取EOF,因此失敗的讀取將有0個字節讀取。 – 2010-08-31 19:04:33

相關問題