C語言隐式聲明與GCC内建函數
- C語言隐式聲明與GCC内建函數
- 什麼是C語言的隐式聲明
- GCC内建函數
- 隐式聲明帶來的災難
什麼是C語言的隐式聲明
在C語言中,函數在調用前不一定非要聲明。如果沒有聲明,那麼編譯器會自動按照一種隐式聲明的規則,為調用函數的C代碼産生彙編代碼。下面是一個例子:
#include <stdio.h>
int main() {
double x = no_declare_func();
return ;
}
$ 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 ;
}
在連結的時候會報錯,因為連結過程中沒有找到函數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
隐式聲明帶來的災難
不要用隐式聲明!!!不要用隐式聲明!!!不要用隐式聲明!!!
- 首先,隐式聲明是預設int型,如果沒有對應同名的内建函數,編譯不報錯,連結報錯,這種情況上面已經介紹
- 有同名的内建函數,且類型相同,gcc編譯連結沒問題
- 有同名的内建函數,類型不同,連結報warning“隐式聲明與内建函數不相容”,但是以内建函數的函數原型為準。gcc編譯器在編譯時能夠自動在常用庫頭檔案(内建函數)中查找與隐式聲明同名的函數,如果發現兩者并不相同,則會按照内建函數的聲明原型去生成調用代碼。
case 2:
#include <stdio.h>
int main(){
int x = abs(-,,,,);
printf("%d \n", x);
return ;
}
其中,abs的隐式聲明函數原型為:
int abs(int);
abs()内建函數原型為:
int abs(int);
gcc編譯連結均沒有報錯,執行結果如下:
$ gcc -c implicitDeclare.c
$ gcc implicitDeclare.o -o implicitDeclare
$ ./implicitDeclare
可見,gcc的内建函數機制并不關心函數的參數,隻是關心函數的傳回值。雖然這個例子的運作結果都是正确的,但是這種正确是“碰巧”的,因為額外的函數參數并沒有影響到結果。這種偶然正确是程式中要避免的。
case 3:
#include <stdio.h>
int main(){
double x = sqrt();
printf("%lf \n", x);
return ;
}
其中,sqrt()的隐式聲明函數原型為:
int sqrt(int);
sqrt()的内建函數原型為:
double sqrt(double);
編譯報警告,連結按照内建函數原型連結:
$ gcc -c implicitDeclare.c
implicitDeclare.c: In function ‘main’:
implicitDeclare.c::: warning: incompatible implicit declaration of built-in function ‘sqrt’ [enabled by default]
double x = sqrt();
^
$ gcc implicitDeclare.o -o implicitDeclare
但是仍然可以執行,結果如下:
$ ./implicitDeclare