日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

c语言 隐式声明,关于C#:隐式函数声明和链接

發(fā)布時(shí)間:2025/3/15 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言 隐式声明,关于C#:隐式函数声明和链接 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近,我了解了C語(yǔ)言中的隱式函數(shù)聲明。主要思想很明確,但在這種情況下,我對(duì)理解鏈接過(guò)程有些麻煩。

考慮以下代碼(文件a.c):

#include

int main() {

double someValue = f();

printf("%f

", someValue);

return 0;

}

如果我嘗試編譯它:

gcc -c a.c -std=c99

我看到有關(guān)函數(shù)f()的隱式聲明的警告。

如果我嘗試編譯和鏈接:

gcc a.c -std=c99

我有未定義的參考錯(cuò)誤。 所以一切都很好。

然后添加另一個(gè)文件(文件b.c):

double f(double x) {

return x;

}

并調(diào)用下一個(gè)命令:

gcc a.c b.c -std=c99

令人驚訝的是,一切都成功地鏈接了。 當(dāng)然,在./a.out調(diào)用之后,我會(huì)看到一個(gè)垃圾輸出。

因此,我的問(wèn)題是:具有隱式聲明的函數(shù)的程序如何鏈接? 在我的示例中,在編譯器/鏈接器的作用下會(huì)發(fā)生什么?

我在SO上讀了許多這樣的話題,但仍然有問(wèn)題。

首先,由于C99,從標(biāo)準(zhǔn)中刪除了函數(shù)的隱式聲明。編譯器可能支持此功能以編譯舊代碼,但這不是強(qiáng)制性的。引用標(biāo)準(zhǔn)序言,

remove implicit function declaration

也就是說(shuō),根據(jù)C11第6.5.2.2節(jié)

If the function is defined with a type that does not include a prototype, and the types of

the arguments after promotion are not compatible with those of the parameters after

promotion, the behavior is undefined.

所以,就您而言,

函數(shù)調(diào)用本身是隱式聲明(自C99以來(lái)已成為非標(biāo)準(zhǔn)聲明),

并且由于函數(shù)簽名的不匹配[假定函數(shù)的隱式聲明具有返回類型int],您的代碼將調(diào)用未定義的行為。

僅添加一點(diǎn)參考,如果您在調(diào)用后嘗試在同一編譯單元中定義函數(shù),由于簽名不匹配,您將收到編譯錯(cuò)誤。

但是,由于函數(shù)是在單獨(dú)的編譯單元中定義的(并且缺少原型聲明),因此編譯器無(wú)法檢查簽名。編譯之后,鏈接器將獲取目標(biāo)文件,并且由于鏈接器中沒(méi)有任何類型檢查(并且目標(biāo)文件中也沒(méi)有任何信息),因此可以愉快地鏈接它們。最后,它將最終成功完成與UB的編譯和鏈接。

感謝您的詳細(xì)回答。

這是正在發(fā)生的事情。

如果沒(méi)有f()的聲明,則編譯器會(huì)采用像int f(void)這樣的隱式聲明。然后愉快地編譯a.c。

編譯b.c時(shí),編譯器沒(méi)有f()的任何先前聲明,因此可以從f()的定義中直觀地看出來(lái)。通常,您會(huì)在頭文件中放置f()的聲明,并將其同時(shí)包含在a.c和b.c中。因?yàn)閮蓚€(gè)文件將看到相同的聲明,所以編譯器可以強(qiáng)制執(zhí)行一致性。它將抱怨與聲明不匹配的實(shí)體。但是在這種情況下,沒(méi)有通用的原型可以參考。

在C中,編譯器不會(huì)在目標(biāo)文件中存儲(chǔ)有關(guān)原型的任何信息,并且鏈接程序不會(huì)執(zhí)行任何一致性檢查(不能)。它所看到的只是a.c中未解析的符號(hào)f和b.c中定義的符號(hào)f。它很高興地解析符號(hào),并完成了鏈接。

但是,事情在運(yùn)行時(shí)會(huì)失敗,因?yàn)榫幾g器會(huì)根據(jù)在此假設(shè)的原型在a.c中設(shè)置調(diào)用。哪個(gè)與b.c中的定義不匹配。 f()(來(lái)自b.c)將從堆棧中獲取一個(gè)垃圾參數(shù),并將其返回為double,在a.c中返回時(shí)將被解釋為int。

我認(rèn)為編譯器在處理隱式聲明時(shí)采用int f()而不是int f(void)。

病態(tài)檢查,但考慮到a.c中的調(diào)用沒(méi)有參數(shù),因此假設(shè)int f(void)是有意義的,因?yàn)閕nt f()表示any number of arguments。

隱式聲明在現(xiàn)代C語(yǔ)言中無(wú)效,并且是UB。不像int f(void);那樣提供隱式的。它僅提供類似int f();的聲明,編譯器在編譯b.c時(shí)不會(huì)" intuit",并且不需要事先定義原型。函數(shù)定義也提供其原型。如果以前提供過(guò)原型,則對(duì)其進(jìn)行檢查。否則,不會(huì)。"通用原型"不是一回事。原型是否可用。與編譯器如何獲取該信息無(wú)關(guān)(通過(guò)頭文件或?qū)嶋H定義等)。

雖然(3)和(4)很好,但在標(biāo)準(zhǔn)中將其簡(jiǎn)單定義為未定義的行為。

@ I3x所有這些都是問(wèn)題的外圍部分,并且大多是在挑剔我表達(dá)某些觀點(diǎn)的方式。但是無(wú)所謂。

How are programmes with implicitly declared functions are linked? And what happens in my example under the hood of compiler/linker?

自C99以來(lái),隱含的int規(guī)則已被C標(biāo)準(zhǔn)取締。因此,具有隱式函數(shù)聲明的程序是無(wú)效的。

自C99起無(wú)效。在此之前,如果沒(méi)有可見(jiàn)的原型,則編譯器會(huì)隱式聲明一個(gè)具有int返回類型的原型。

Surprisingly everything is linked successfully. Of course after

./a.out invocation I see a rubbish output.

由于您沒(méi)有原型,因此編譯器會(huì)為f()隱式聲明一個(gè)類型為int的原型。但是f()的實(shí)際定義返回double。兩種類型不兼容,這是未定義的行為。

即使在C89 / C90中,這也是未定義的,在C89 / C90中,隱式int規(guī)則有效,因?yàn)殡[式原型與實(shí)際的f()返回類型不兼容。因此,此示例在所有C標(biāo)準(zhǔn)中均未定義(a.c和b.c)。

具有隱式函數(shù)聲明不再有用或無(wú)效。因此,有關(guān)編譯器/鏈接器處理方式的實(shí)際細(xì)節(jié)僅具有歷史意義。它可以追溯到K&R C的標(biāo)準(zhǔn)前時(shí)間,后者沒(méi)有函數(shù)原型,并且函數(shù)默認(rèn)返回int。將功能原型以C89 / C90標(biāo)準(zhǔn)添加到C中。最重要的是,對(duì)于有效的C程序中的所有函數(shù),必須具有原型(或在使用前定義函數(shù))。

這還不完整。這個(gè)問(wèn)題與隱式聲明無(wú)關(guān),但是由于鏈接器對(duì)類型一無(wú)所知,他找到了一個(gè)名為f的函數(shù)的定義,該函數(shù)適用于鏈接。為了避免這種問(wèn)題,某些語(yǔ)言使用名稱修飾將代碼類型編碼到函數(shù)名稱中。但是在C語(yǔ)言中不是這樣。擁有原型是不夠的,您需要一致的原型!

@ Jean-BaptisteYuns我已經(jīng)解釋過(guò),隱式原型的類型與實(shí)際類型不兼容,因此UB被調(diào)用。沒(méi)有"一致原型"之類的東西。原型是有關(guān)函數(shù)返回類型及其參數(shù)的完整信息。

@ i3x,但最大的問(wèn)題(我認(rèn)為)是鏈接為什么完成,以及解釋鏈接過(guò)程的詳細(xì)信息。

@ Jean-BaptisteYuns是的,主要的誤解是關(guān)于這種情況下的鏈接問(wèn)題。因此,我閱讀了Sourav和l3x的答案。所以他們有點(diǎn)混在我的頭上。現(xiàn)在,Souravs的答案似乎更加完整。

@Ziffusion我是說(shuō)它的UB,并且由于C.Btw的古老規(guī)則而被編譯和鏈接,我只是讀了您的答案,它并不完全準(zhǔn)確。

@ i3x我想你錯(cuò)過(guò)了重點(diǎn)。主要原因是:原型不一致(隱式聲明邊界效應(yīng))和無(wú)類型鏈接。兩者都與"古代C規(guī)則"無(wú)關(guān)。

編譯后,所有類型信息都將丟失(調(diào)試信息中可能除外,但鏈接程序不會(huì)對(duì)此進(jìn)行注意)。唯一剩下的就是"在地址0xdeadbeef處有一個(gè)名為" f"的符號(hào)"。

標(biāo)頭的目的是告訴C符號(hào)的類型,包括對(duì)于函數(shù)而言,它采用什么參數(shù)以及它返回什么。如果將實(shí)際值與聲明的值(顯式或隱式)不匹配,則會(huì)得到未定義的行為。

總結(jié)

以上是生活随笔為你收集整理的c语言 隐式声明,关于C#:隐式函数声明和链接的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。