2016-01-09 52 views
4

採取我有簡單的應用程序:什麼默認庫同時編譯C項目,GCC

#include <stdio.h> 
int main(int argc, char ** argv) 
{ 
    printf("hello"); 
    exit(0); 
} 

當我用命令編譯

gcc -c count_words.c 

我警告:

warning: incompatible implicit declaration of built-in function ‘exit’ [enabled by default] 
    exit(0); 

我試圖找到exit()函數的定義。並發現它在stdlib.h中定義。但它不包含在我的項目中,並且在編譯命令中沒有定義其他庫。

糾正我,如果我錯了,但看起來像gcc需要一些庫作爲默認值。這些庫是什麼,是否有可能告訴gcc不包括它們?

爲什麼編譯器不喜歡exit(0)假設它包含stdlib.h作爲默認?

+0

相關:http://stackoverflow.com/q/8930641/3049655 –

+1

你在混淆包括標題和鏈接到庫。這是兩個完全不同的東西。 – Mat

+0

那麼,在哪個庫退出(int)存在?而我的編譯命令不包含任何庫。 – vico

回答

1

假設它以默認方式包含stdlib.h?

它根本就沒有。這不符合標準。

所以,當你使用exit時,它從來沒有被聲明過,所以你在使用時隱式聲明。然而,你在其他地方實施exit的事實只會成爲最終聯繫中的問題。

現在,海灣合作委員會知道你很快就會陷入困境,所以它警告你。

只是實際上包括stdlib.h,你應該沒問題。

+1

另請注意,隱式函數聲明自C99 IIRC以來無效。 – juanchopanza

-5

您的代碼適用於警告而不是錯誤。如果添加

#include <stdlib.h> 

然後沒有警告了;有問題)

+1

這不回答這個問題,只是告訴OP已經知道的東西。 –

1

「庫」 是gcc/builtins.def從GCC源文件目錄。

這不僅僅是一個頭文件,它不提供聲明供您使用。但它有適當的原型來檢查你的反對。

調用未申報的exit()的隱式聲明的結果是這樣的:

int exit(int); 

搜索血淋淋的細節 「C隱含的聲明」。然而在這種情況GCC有來自builtins.def自己的原型退出():

void exit(int) __attribute__((nothrow,noreturn)); 

這些聲明不匹配,這就是你被警告什麼。

5

讓我們把你的例子:

#include <stdio.h> 

int main(int argc, char ** argv) 
{ 
    printf("hello\n"); 
    exit(56); 
} 

雖然我們得到編譯警告:

~$ gcc test.c -o test 
test.c: In function ‘main’: 
test.c:6:5: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration] 
    exit(56); 
    ^
test.c:6:5: warning: incompatible implicit declaration of built-in function ‘exit’ 
test.c:6:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’ 

無論如何,我認爲你已經嘗試運行它,並確保它的工作原理:

~$ ./test 
hello 
~$ echo $? 
56 

@Mat他說得對:

你在混淆包括標題和鏈接到庫。這些都是 兩個完全不同的事情

C編譯器和鏈接都完全單獨的工具。讓我們看看這個。實際上,這個程序依賴於標準的C庫(因爲所有的程序如果你沒有通過編譯器-nostdlib)和一些系統庫(如loader和vdso)。你可能會看到它:

~$ ldd test 
    linux-vdso.so.1 (0x00007fff1b128000) 
    libc.so.6 => /lib64/libc.so.6 (0x00007f804389f000) 
    /lib64/ld-linux-x86-64.so.2 (0x0000557744537000) 

這三個庫是任何程序的最小集合。在我們的例子中,exit函數在標準庫或libc.so.6中定義。現在我們來看看詳細模式下的編譯過程。您可以通過傳遞-v--verbose選項實現這個編譯器:

gcc test.c -o test --verbose 

如果您將執行此,你會發現這樣的詩句:

#include <...> search starts here: 
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include 
/usr/local/include 
/usr/include 

所以,編譯知道到哪裏尋找頭文件對於stdlib,它開始搜索它以查找非本地函數的聲明。請注意,它僅在您的源代碼文件中包含的頭文件中進行搜索。它可以在stdio.h中找到printf聲明,但找不到exit的聲明。

此步驟後,編譯開始你的程序與庫鏈接:

/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/collect2 ... -lc ... 

哪裏collect2是試圖程序與lc鏈接這是標準C庫GCC UTIL。請注意,該過程由兩個步驟組成:編譯和鏈接。這就是你的程序工作的原因。

此外,gcc支持-M選項,它會告訴你主文件的依賴關係。所以,如果你將執行它,你會看到一組的頭文件,包括stdio.h,但不stdlib.h

$ gcc -M test.c 
test.o: test.c /usr/include/stdc-predef.h /usr/include/stdio.h \ 
/usr/include/features.h /usr/include/sys/cdefs.h \ 
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ 
/usr/include/gnu/stubs-64.h \ 
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h \ 
/usr/include/bits/types.h /usr/include/bits/typesizes.h \ 
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ 
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h \ 
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h 

甚至更​​好,嘗試通過-E選項gcc

$ gcc -E test.c 

和您會在第一階段 - 預處理階段後看到結果。我認爲這是理解你爲什麼得到這個警告的最簡單的方法。

相關問題