是否有任何32位或64位平臺上的int8_t
,int16_t
和int32_t
以不同的方式傳遞?Char vs int調用約定
我在問,因爲OCaml(4.03+,尚未發佈)可以傳遞32或64位整數,並且可以直接加倍到C,但不是8位或16位整數或單精度浮點數。
編輯:基本上我問
char x(char y)
可以被稱爲
int x(int y)
是否有任何32位或64位平臺上的int8_t
,int16_t
和int32_t
以不同的方式傳遞?Char vs int調用約定
我在問,因爲OCaml(4.03+,尚未發佈)可以傳遞32或64位整數,並且可以直接加倍到C,但不是8位或16位整數或單精度浮點數。
編輯:基本上我問
char x(char y)
可以被稱爲
int x(int y)
在調用約定的關鍵詞是公約和慣例不同的原因有很多,即架構等。我可能會使用int8_t
,但在後臺可能會佔用32
位或64位系統64
位。只要它的行爲像int8_t
我不在乎。一種語言可能會暴露一個char
,但它可能被表示爲一個int,C做到這一點。當你深入到比抽象層次更高的語言C語言界面時,你會看到一些編譯器編寫者爲了簡化他們的生活而做出的一些設計決定。
即使如果有32位或64位平臺,通過int8_t
S,int16_t
S和int32_t
不同的方式過(我懷疑有,由於種種原因),那會不會是對的OCaml不找藉口能夠傳遞這樣的論點。所有它需要做的就是遵循平臺的標準ABI,世界就會好起來。很有可能,FFI根本就沒有實現它,因爲它對實施者來說不夠有用。這就是說,爲什麼你不可能找到這樣一個平臺的一個主要原因是因爲大多數C編譯器試圖保留一些,至少是令牌的兼容性,在那裏它不需要聲明函數原型;未聲明的函數將被調用,就好像它們具有參數和返回值int
一樣。由於這樣的原因,幾乎所有的ABI都會將所有整數參數提升爲本地字大小,因此它們將與實際使用的任何具體整數類型分配兼容,即使可以更有效地使用較小的參數單位。
編輯:要回答你的問題,編輯,然後對所有的標準有所ABI的,是的,你可以調用char x(char)
作爲int x(int)
。然而,一個警告可能是,編譯器可能會假定傳遞的字的高位爲零,但是,如果您將(例如)512
作爲使用的參數傳遞,可能會導致未定義的行爲作爲C函數中的char
。
是否有任何32位或64位平臺的int8_t,int16_t和int32_t傳遞不同?
推測存在一個,也許是實驗性的或歷史性的。但是,如果我們將話語範圍限制在OCaml系統支持的一組體系結構(主要實現)中,那麼答案是否定的。
我問,因爲OCaml中(4.03+,還未被釋放)可以 通32位或64位的整數和雙打到C直接,但不是8個或 16位整數或單精密浮動。
原因是因爲OCaml具有不同的整數表示形式。與C表示相比,它向左移一位並遞增。因此0
表示爲C的1
,1
爲3
等等。最低有效位用於區分立即值和指針。所以OCaml整數有效地少了一位,即64位系統上的63位和32位系統上的31位。這一切都意味着,在將一個整數傳遞給c函數之前,您需要將其移到右側。一個簡單和低成本的操作。 char
類型也由int
代表,所以它具有相同的問題。標準庫中沒有int8_t
和int16_t
,所以我不能談論它們。第三方庫可能會以任何形式介紹它們,可能支持也可能不支持直接傳遞給C函數。
OCaml中的int32
,int64
,nativeint
和float
,都表示爲裝箱值,即它們OCaml中的堆被分配並圍繞OCaml的功能通過用作指針。分配的塊的表示與C
中的相同,因此允許按原樣傳遞它。當然,只有被調用的函數沒有將這個值存儲在某個地方,並且不會調用任何可能引發垃圾回收的函數,這纔是安全的。在4.03之前,程序員需要通過將內容複製到C變量(安全方式),或者直接解引用並傳遞它(一種危險的方式 - 你應該知道你在做什麼)來解開值。 4.03版本提供了新的註釋(屬性unboxed
),這是對以前存在的"%float"
註釋的概括。這個註解允許直接傳遞這四種類型的值。此註釋適用於有限的一組函數類型,當然,僅對特定函數是安全的。
因此,總而言之,小整數以非常快的速度傳遞給C.盒裝值通常需要一些額外的工作,這也引入了對垃圾收集和分配的調用。爲了減輕這一點,4.03增加了一些優化,如果它是安全的,可以直接傳遞它們。
編輯:基本上我問
char x(char y)
可以被稱爲
int x(int y)
但從OCaml的外部函數接口點沒有大區別。唯一的問題是,OCaml int
比C int
小,因此如果x
可能返回一個值,但不適合OCaml表示,應該使用更大(和盒裝)類型,例如nativeint
。在很多情況下,這個問題可以忽略,例如,當int
是錯誤代碼,或者已知它很小或不大於輸入參數。
我無法想象任何架構上的任何調用約定都會允許在任何現代系統中使用該約定。對於基於寄存器的調用約定,每個參數都放在一個寄存器中。我不希望任何編譯器嘗試分配寄存器的一部分,這是全部或沒有。無論如何,這可能會非常低效。對於基於堆棧的版本,您通常以字大小的塊來推送參數,否則會導致錯位。而且,效率很低。 –
@JeffMercado:並不是說它與這個問題有關,但是當傳遞某些結構時,編譯器確實將「寄存器的部分」分配給結構字段。例如,一個'struct {int a,b;}'將在AMD64上的一個reigster中傳遞,其中一半寄存器用於每個字段。 – Dolda2000