我正在閱讀教程,我已經閱讀那裏,我們不能定義void main()
作爲原型已經定義爲int main() or int main(int argc , char *argv)
這些只是兩個有效的方式來定義C中的主要功能。 所以在哪個頭文件或庫文件這些原型設置爲 我不知道如何編譯器給出錯誤float main()
後面的機制是什麼,我的意思是它是一個語法錯誤或爲main()定義的一些原型?c或C++中main()函數的原型?
請用簡單的語言給出答案。
我正在閱讀教程,我已經閱讀那裏,我們不能定義void main()
作爲原型已經定義爲int main() or int main(int argc , char *argv)
這些只是兩個有效的方式來定義C中的主要功能。 所以在哪個頭文件或庫文件這些原型設置爲 我不知道如何編譯器給出錯誤float main()
後面的機制是什麼,我的意思是它是一個語法錯誤或爲main()定義的一些原型?c或C++中main()函數的原型?
請用簡單的語言給出答案。
棒的標準形式,
int main(int argc, char* argv[])
或
int main(void)
,如果你從一個編譯器的移動程序到另一個你不會遇到問題。
這就是說,ISO/IEC 9899:201X - > 5.1.2.2.1(程序啓動)啓動狀態:
稱爲在程序啓動的功能被命名爲主力。 實現聲明沒有原型這個函數。它應 與的INT返回類型和不帶參數進行定義:
int main(void) { /* ... */ }
或兩個參數(這裏稱爲argc和argv,雖然任何 名稱可以使用,因爲它們是地方於它們是 聲明的功能):
int main(int argc, char *argv[]) { /* ... */ }
或等同物; 10)或某種其他實施方式定義的 方式。 。
。
。
10)因此,int可以被定義爲int的 typedef名稱替代,或者argv的類型可以被寫爲 char ** argv,依此類推。
問題中沒有提到託管環境。您通過引用託管環境的子章節來錯誤地引用標準,從而忽略了標準中獨立環境的整個章節。 – Lundin
我不認爲有主函數的原型。這是您的程序的入口點,它由標準定義。
例如C標準定義是這樣:
5.1.2.2.1計劃啓動
1名爲在程序啓動的功能被命名爲主力。 實現聲明此函數沒有原型。應當帶有int返回類型和不帶參數來 定義:
int main(void){}
或具有兩個參數(此處稱爲argc和argv,雖然任何名字>可以使用,因爲它們是本地的在它們 聲明功能):
int main(int argc, char *argv[]){}
或等同物; 9)或在一些其它實現定義的方式。
問題中沒有提到託管環境。您通過引用託管環境的子章節來錯誤地引用標準,從而忽略了標準中獨立環境的整個章節。 – Lundin
C11 Standard指示什麼是有效的和無效的C(舊標準具有相同的規則)。
在對於main
簽名它說(5.1.2.2.1):
稱爲在程序啓動的功能被命名爲主力。該實現沒有聲明這個函數的原型。它應爲int的返回類型和不帶參數進行定義:
int main(void) { /* ... */ }
或兩個參數(這裏稱爲argc和argv,雖然可以使用任何名字,因爲他們是當地的在其中聲明它們的功能):
int main(int argc, char *argv[]) { /* ... */ }
或同等或在一些其它實現定義的方式。
所以,除了一些其他實現定義的方式,唯一有效的簽名都是這兩個。 如果一個實現定義了一個不同的簽名,您可以自由使用該簽名,前提是您不介意丟失一些代碼可移植性。
所以下面都是一個編譯器無效無額外:
int main() { /* ... */ }
void main() { /* ... */ }
void main(void) { /* ... */ }
double main() { /* ... */ }
int main(int argc, double *argv[]) { /* ... */ }
int main(int argc, char **argv, char **envp) { /* ... */ }
你的教程是不完全錯,但它描述了一個非常嚴格執行的行爲,比C標準嚴格要求的實現成爲。
C標準中關於程序啓動時調用的函數的說法就是某些可能性需要工作。它並不是說需要其他東西而不是才能工作。另外,C標準對編譯器錯誤的說法很少。現代C實現通常超出標準對診斷的要求;支持他們接受的一套程序的許多擴展也是很常見的。
在「託管」的環境,一個提供所有的標準C庫,讓啓動名稱和簽名int main(void)
或int main(int argc, char **argv)
被符合呼籲程序的功能程序的設施。他們需要工作。但是這個標準允許這個函數被「以某種其他實現定義的方式」進行聲明,並且存在許多替代名稱和簽名:我將列出一些最常見的名稱和簽名。
int main(int argc, char **argv, char **envp)
void main(void)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
如果它支持這些替代入口點的名稱或簽名之一的執行文件,這是完全可以使用它。 (你的程序將不會是「嚴格符合」,但幾乎沒有真正的計劃是「嚴格符合」,所以不要擔心。)
在一個「獨立」的環境,這不提供所有的標準C庫中,在程序啓動時調用的函數的名稱和簽名留給實現 - 您可能不得不使用諸如EFI_STATUS efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
之類的古怪東西。 但是,int main(void)
可以正常工作,而int main(int argc, char **argv)
可以正常工作(在運行時收到的參數可能是垃圾)。現在
,如果你有一個託管環境中會發生什麼,你使用了一個沒有記錄工作的入口點函數的名稱和/或簽名? C標準說你的程序在這種情況下有未定義行爲- 什麼都可以發生。一些常見的事情將會發生:
編譯器確實發出了一個錯誤或至少是一個警告。它沒有從任何頭文件獲取正確的原型;相反,正確的原型據說是內置於的編譯器,在編譯器自己的源代碼中定義。現在很多C庫函數以及main
都是這種情況。演示:
$ cat > test.c <<\!
extern int exit(int); // wrong, `exit` should return `void`
void main(void) {} // wrong, `main` should return `int`
!
$ gcc -fsyntax-only -std=gnu11 -Wall test.c
test.c:1:12: warning: conflicting types for built-in function ‘exit’
test.c:2:6: warning: return type of ‘main’ is not ‘int’
(由於歷史原因,GCC是幾乎沒有挑剔別人的代碼,因爲它可能是,很多的事情,從現代的眼光看,應該是錯誤僅僅是警告,並如果你從頭開始編寫新的代碼並使用GCC,我建議基本上總是使用-std=gnu11 -Wall -Wextra -Wpedantic -Werror
選項,但不是-std=c11
,因爲這會使關閉您可能需要的擴展名,並且可以也暴露系統頭文件中的錯誤)。
prog內存無法鏈接。這是什麼情況,舉例來說,如果你試圖彌補自己的名字,而不是調用它main
:
$ cat > test.c <<\!
extern int puts(const char *);
void my_program_starts_here(void) { puts("hello world"); }
!
$ gcc -std=gnu11 -Wall test.c
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:
In function `_start':
(.text+0x20): undefined reference to `main'
這是更神祕的錯誤,你可以走出連接器中的一個,所以我將它解開一點。你有沒有想過如何調用main
?這是令人驚訝的簡單:有C庫提供的功能,通常被稱爲_start
,其最後一行是一樣的東西
exit(main(argc, argv, environ));
由於歷史原因,該功能不與libc.so
大部分C庫的捆綁。它位於一個單獨的目標文件crt1.o
中,編譯器在被要求鏈接一個程序時會自動引入(就像它自動在-lc
上一樣)。因此,當您未定義main
時,從_start
對main
的引用不滿足,並且鏈接失敗。
(OK,如何_start
被調用這就是你進入更深的魔法問另外一個問題嗎?)
最後,程序可以編譯和鏈接罰款,甚至出現正常工作 - 但看起來更難,你發現它是行爲不端。如果您在Unix系統上使用void main(void)
,會發生這種情況。 (一階,除Windows以外的所有託管的環境是Unix系統現在。)
$ cat > test.c <<\!
extern int puts(const char *);
void main(void) { puts("hello world"); }
!
$ gcc -std=gnu11 test.c
$ ./a.out
hello world
沒有-Wall
,而不是從編譯器窺視,程序運行罰款......或者做的?
$ ./a.out ; echo $?
hello world
12
該數字應從main
返回的值成爲該程序的exit status,其出現在殼可變$?
。如果main
已正確聲明爲返回int
,並且末尾有return 0;
,則echo $?
將打印0.從哪裏來的?可能是puts
的返回值,編譯器在從main
返回之前沒有打擾從返回值寄存器中清除。
很容易沒有注意到這個錯誤,但它是一個錯誤,並且第一個嘗試編寫涉及你的程序的shell腳本的人將會對你很惱火。
有關退出狀態的一些註解,主要用於學究:
在C++中,並用C開始與1999年的標準,你在技術上允許省略任何明確return 0;
在main
只要你聲明正確,但我認爲依靠這是糟糕的風格。
在Unix上的很多,但並非所有的實現,在$?
中顯示的值將只能從main
返回的值低了七八位。這是用於檢索子進程退出狀態的系統調用的一個限制,waitpid
。
甲嚴格符合 ISO C程序只能從main
返回三個值:0,EXIT_SUCCESS
,和EXIT_FAILURE
;後兩個常量在stdlib.h
中聲明。從main
返回零的效果保證是一樣返回EXIT_SUCCESS
的效果,但不能保證的值相等。
在實踐中,返回至少0,1和2以及其中EXIT_SUCCESS != 0
和/或EXIT_FAILURE != 1
早已走到天空中的一大桶的實現是安全的,所以不用擔心它。
這裏沒有任何原型。這個限制是編譯器本身的一部分。 – HolyBlackCat
「這些只是C中定義主函數的兩種有效方式」 - > _almost_。這些(和等價物)只有兩個_defined_有效的方法。其他可能存在的每個實施可能會失去可移植性, – chux
因爲每個發佈的答案都包含事實錯誤,所以會投票刪除投票。所以這篇文章造成的傷害比好的更多。如果沒有錯誤地引用這些標準,請參閱標準實際所說的內容[閱讀本文](https://stackoverflow.com/a/31263079/584518)。 – Lundin