程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 一個疏忽引發的思考!(strerror),疏忽strerror

一個疏忽引發的思考!(strerror),疏忽strerror

編輯:關於C語言

一個疏忽引發的思考!(strerror),疏忽strerror


  前幾天寫代碼因為自己的疏忽導致一遍又一遍的Segmentation fault (core dumped)。該問題是因為strerror(errno)返回的指針指向非法的內存導致程序打印錯誤時崩潰。

  嘗試數次無果,為了進度。簡單粗暴的換成了perror(str)。今天忙裡偷閒,定位到了問題做個記錄和分享。

  所有的坑,都是自己挖的。開始正題。

  

  1 #include<stdio.h>
  2 #include<errno.h>
  3 //#include<string.h>
  4 int main()
  5 {
  6     char *perr = NULL;
  7     errno = 14;
  8     perr = strerror(errno);
  9     puts(perr);
 10     return 0;
 11 } 

  先看代碼,上述我屏蔽了#include<string.h>。如我所料,編譯通過(其實有warn已經告訴你有問題了),運行崩潰了。warn如下:

  

  然後加上#include<string.h>程序完美編譯,完美成功執行。為什麼呢?經過與人(CSDN某某某)討論和浏覽stackoverflow上的帖子,以及我最終使用gcc -E預編譯  gcc -Wall的驗證。

  

  我得到以下結論。

  1.strerror()函數聲明在string.h頭文件裡(我以前以為是在errno.h裡的,還是基本功不行啊)。

  2.gcc編譯時如果發現未定義的函數,它會認為該函數是定義在其他源文件中的,所以編譯是通過的。

  但是因為編譯器看不見函數原型,所以它認為函數返回值為int。在鏈接階段,如果找到該函數則通過,找不到則報錯。
    這裡我做了個實驗,如果函數原型在.o文件裡鏈接後沒有問題,連接器會修正返回值類型。但是如果鏈接的是.so文件,則返回值就是int。我也想不明白。

  

  揭曉答案吧!我的程序為什麼會報錯呢?這是一系列疏忽大意加基本功不扎實的惡果。

  因為我沒有包string.h。所以編譯器看不見函數原型,默認函數返回值為int。並給出了wara:assignment makes pointer from integer without a cast(用一個int型給指針賦值而沒有轉換--英文不好)。顯而易見,在64位系統中char*是64位的,int是32位。所以相當於我用32位的整型值當作地址賦值給了指針。所以指針指向非法內存。接著Segmentation fault (core dumped)就登場了。

  系統中類型於strerror()這種返回指針的函數都可能有類似問題,所以頭文件該包的還是要包上。該注意的warn還是不容忽視啊。

  文章到此已經結束,給個附錄。64位系統 gcc編譯器 各個數據類型長度表。

  

  
  以上闡述由非權威人士撰寫。如有大牛深谙其理,歡迎跟帖深入說明。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved