[英]C++ by-reference argument and C linkage
我遇到了一段代碼(包含XLC8和MSFT9編譯器),包含一個帶有C鏈接和引用參數定義的函數的C ++文件。 這讓我很煩,因為引用只是C ++。 有問題的函數是從C代碼調用的,它被聲明為將指針參數取代到相同的類型而不是引用參數。
簡化示例 :
C ++文件 :
extern "C" void f(int &i)
{
i++;
}
C檔案 :
void f(int *);
int main()
{
int a = 2;
f(&a);
printf("%d\n", a); /* Prints 3 */
}
現在,街上的一句話就是大多數C ++編譯器,它們都像指針一樣實現引用。 是這樣的,只是純粹的運氣,這個代碼工作的原因,或者說它在C ++規范中的某處說明當你用引用參數和C鏈接定義一個函數時的結果是什么? 我無法找到任何相關信息。
在許多情況下,但不是全部,可以使用“自動解除引用”指針實現引用。 在C ++標准中,任何特定的編譯器都不會以這種方式處理具有C鏈接和引用參數的函數,您應該將其視為實現細節。
編寫一個帶指針並調用函數的轉發函數並不難,如果你需要這樣做而不依賴於實現細節:
void real_f(int& n) {
n++;
}
extern "C" void f(int* p) { // called from C code
real_f(*p);
}
我的副本n3000.pdf(從這里開始 ),在7.5節 - 鏈接規范中有這個說法:
9 。 從C ++到在其他語言中定義的對象以及從其他語言在C ++中定義的對象的鏈接是實現定義的和語言相關的。 只有在兩種語言實現的對象布局策略足夠相似的情況下才能實現這種聯系。
由於C和C ++是不同的語言,這意味着你不能依賴常見編譯器的這個“特性”。
強調是同一部分中的注釋5(強調我的):
如果兩個聲明聲明具有相同名稱的函數,並且參數類型列表(8.3.5)是同一命名空間的成員,或者聲明具有相同名稱的對象是同一命名空間的成員,並且聲明為這些名稱提供不同的語言鏈接,該計划是不正常的; 如果聲明出現在不同的翻譯單元中,則無需診斷 。
所以,我想說你所做的並不能保證按照標准工作,並且編譯器不需要為你給出的例子打印診斷因為聲明在不同的翻譯單元中 。
僅供參考,在Snow Leopard上使用gcc和g ++版本4.2.1“對我有用”。
引用是對象的備用名稱。 從技術上講,C中沒有任何東西可以直接映射到C ++引用。
引用的明顯實現是作為(常量)指針,每次使用時都會解除引用。 因此,根據編譯器如何實現引用,您的代碼可能會起作用。 但這不正確。
解決方案是編寫一個C函數,它接收一個真實對象或指向該對象的指針,並從中調用C ++函數。
我想你已經得到了一些好的答案,所以只是在你的問題上指出一些額外的東西。
我謙虛的理解是,extern只是創造了一個C符號。
所以即使我添加一個類對象,你的例子仍然“似乎工作”(gcc / g ++) - 我不得不嘗試相信它:
class A {};
extern "C" void f(int &i, A a) {
i++;
}
這就是Bjarne Stroustrup對引用的看法:
“ 大多數引用是使用指針變量實現的實現;它通常占用一個內存字。但是,純粹本地使用的引用可以 - 通常是 - 由優化器消除 ”。
例如:
struct S
{
int a;
int b[100];
}; // just an example
void do_something(const vector<S>& v)
{
for (int i=0; i<v.size(); ++i)
{
int(&p)[100] = v[i].b;
for (int j=0; j<100; ++j)
cout <<p[j];
}
}
在這種情況下,p不需要存儲在存儲器中(可能它只存在於寄存器中,也許它會消失在指令中)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.