隱式聲明與GCC內建函數

C語言隱式聲明與GCC內建函數

什麼是C語言的隱式聲明

  在C語言中,函數在調用前不一定非要聲明。如果沒有聲明,那麼編譯器會自動按照一種隱式聲明的規則,爲調用函數的C代碼產生彙編代碼。下面是一個例子:

#include <stdio.h>

int main() {
    double x = no_declare_func();
    return 0;
}
$ gcc -c implicitDeclare2.c 
$ gcc implicitDeclare2.o -o implicitDeclare2
implicitDeclare2.o: In function `main':
implicitDeclare2.c:(.text+0xe): undefined reference to `no_declare_func'
collect2: error: ld returned 1 exit status

  可以看到上面的代碼沒有定義no_declare_func,但是gcc在編譯的時候並不會報錯,因爲C語言規定,對於沒有聲明的函數,自動使用隱式聲明,也就變成如下代碼(函數的隱式聲明默認爲int型):

#include <stdio.h>

int no_declare_func();
int main() {
    double x = no_declare_func();
    return 0;
}

  在鏈接的時候會報錯,因爲鏈接過程中沒有找到函數no_declare_func的定義。
  目前C++是沒有隱式聲明這一說,遇到這種沒有函數聲明的情況,會直接報error。

GCC內建函數

  內建函數(built-in),即一個系統或者工具提供的默認就能用的函數,我的理解是默認情況下,gcc在鏈接的時候如果沒有找到定義,就會自動去鏈接庫中對應名稱的函數,gcc的內建函數大多是爲了對代碼進行優化。
  gcc內建函數相關的選項如下:

  • -fbuiltin:
    gcc編譯默認選項,默認通過名字來識別內建函數

  • -fno-builtin:
    禁用GCC編譯器內建函數。如果在gcc編譯時用了-fno-builtin選項,則除非利用前綴__builtin_進行引用,否則不識別所有內建函數。例如,爲了獲得內建strcpy函數,應該調用__builtin_strcpy()而不是名爲 strcpy() 的函數。

  • -fno-builtin-xxx:
    gcc編譯時想特定的不使用某些函數的內建函數,例如,想使用除sqrt()之外的所有內建函數,則可以添加此選項-fno-builtin-sqrt

隱式聲明帶來的災難

  不要用隱式聲明!!!不要用隱式聲明!!!不要用隱式聲明!!!

  1. 首先,隱式聲明是默認int型,如果沒有對應同名的內建函數,編譯不報錯,鏈接報錯,這種情況上面已經介紹
  2. 有同名的內建函數,且類型相同,gcc編譯鏈接沒問題
  3. 有同名的內建函數,類型不同,鏈接報warning“隱式聲明與內建函數不兼容”,但是以內建函數的函數原型爲準。gcc編譯器在編譯時能夠自動在常用庫頭文件(內建函數)中查找與隱式聲明同名的函數,如果發現兩者並不相同,則會按照內建函數的聲明原型去生成調用代碼。

case 2:

#include <stdio.h>

int main(){
    int x = abs(-1,2,3,4,5);
    printf("%d \n", x);
    return 0;
}

  其中,abs的隱式聲明函數原型爲:

int abs(int);

  abs()內建函數原型爲:

int abs(int);

  gcc編譯鏈接均沒有報錯,執行結果如下:

$ gcc -c implicitDeclare.c
$ gcc implicitDeclare.o -o implicitDeclare
$ ./implicitDeclare 
1 

  可見,gcc的內建函數機制並不關心函數的參數,只是關心函數的返回值。雖然這個例子的運行結果都是正確的,但是這種正確是“碰巧”的,因爲額外的函數參數並沒有影響到結果。這種偶然正確是程序中要避免的。

case 3:

#include <stdio.h>

int main(){
    double x = sqrt(1);
    printf("%lf \n", x);
    return 0;
}

  其中,sqrt()的隱式聲明函數原型爲:

int sqrt(int);

  sqrt()的內建函數原型爲:

double sqrt(double);

編譯報警告,鏈接按照內建函數原型鏈接:

$ gcc -c implicitDeclare.c
implicitDeclare.c: In function ‘main’:
implicitDeclare.c:4:16: warning: incompatible implicit declaration of built-in function ‘sqrt’ [enabled by default]
     double x = sqrt(1);
                ^
$ gcc implicitDeclare.o -o implicitDeclare

但是仍然可以執行,結果如下:

$ ./implicitDeclare 
1.000000 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章