[英]Complicated when compiling in c++ but not in c (gcc)
我在c ++中有乘法聲明的問題,但在c中卻沒有。 您可以查看代碼以獲取更多信息。
文件main.c
#ifndef VAR
#define VAR
int var;
#endif
int main(){}
文件other.c
#ifndef VAR
#define VAR
int var;
#endif
用gcc編譯
gcc main.c other.c
>> success
用g ++編譯
g++ main.c other.c
Output:
/tmp/ccbd0ACf.o:(.bss+0x0): multiple definition of `var'
/tmp/cc8dweC0.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
我的gcc和g ++版本:
gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
由於變量var
多個定義,您的代碼在C和C ++中都是正式錯誤的。 只是這種類型的錯誤傳統上被C編譯器忽略為一種流行的非標准擴展。 在C語言規范中甚至提到了這個擴展
J.5常用擴展
以下擴展在許多系統中廣泛使用,但不能移植到所有實現。 [...]
J.5.11多個外部定義
對象的標識符可能有多個外部定義,有或沒有明確使用關鍵字extern; 如果定義不一致,或者初始化了多個,則行為未定義(6.9.2)。
但正式地說,在C和C ++語言中,你有完全相同的多重定義錯誤。 請求你的C編譯器更迂腐(禁用擴展,如果它有一個選項),你的C編譯器也應該生成與C ++編譯器相同的錯誤。
同樣,您的代碼包含變量var
多個定義,這在C和C ++中都是錯誤的。 你的#ifdef
指令根本沒有解決任何問題。 Preperocessor指令在這里無法幫助你。 預處理器在每個翻譯單元中本地和獨立地工作。 它無法跨翻譯單位看到。
如果要創建全局變量(即所有翻譯單元共享的相同變量),則需要對該變量進行一個且僅一個定義
int var;
在一個且只有一個翻譯單元。 所有其他翻譯單元應接收var
非定義聲明
extern int var;
后者通常放在頭文件中。
如果您需要在每個翻譯單元中使用獨立的變量var
,只需在每個翻譯單元中將其定義為
static int var;
(盡管在C ++中, static
這種用法現在已被棄用並被無名空間名稱取代)。
這兩個#define
指令彼此無關,因為它們位於不同的轉換單元(即源文件)中。 編譯器以完全隔離的方式處理兩個源文件,因此defined(VAR)
始終為false,並且始終包含#ifndef
的內容。
如果你的意思是在多個源文件之間共享一個變量,有一種簡單的方法可以解決它:在一個源文件中定義它,並在另一個源文件中聲明它:
// other.cpp
int var; // Definition.
// main.cpp
extern int var; // Declaration.
鏈接時,這些將引用相同的var
。 更好的是,在標頭中聲明變量:
// other.h
extern int var;
然后需要var
文件可以只包含標題:
// main.cpp
#include "other.h"
您在C和C ++之間觀察到的差異與C與C ++中全局聲明的標識符的處理有關。 在C中,任何數量的暫定定義 (沒有存儲類說明符和初始化程序)都可以由鏈接器合並到一個符號中 - 只要該符號的所有實際定義最終具有相同的鏈接和存儲類。 這是使用弱鏈接符號完成的。
但是,C ++沒有暫定定義的概念,並且將沒有存儲類說明符的外部聲明視為定義。 因此,G ++生成強大的鏈接器符號,導致鏈接時發生沖突。
編譯模塊中全局變量的可見性在C和C ++之間略有不同。
如果它們是不同的變量,請將它們包含在每個文件的匿名命名空間中。
namespace {
int var;
}
如果它們是SAME變量,則其中一個需要extern
decl-specifier,以避免多個定義。
extern int var;
您的#define VAR
在您發布的示例中沒有做任何事情。 該定義不是跨編譯模塊進行的。
包容性保護是翻譯單位的本地保護。 這意味着當您在一個.cpp
文件中執行#define VAR
時,它不會在任何其他文件中定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.