簡體   English   中英

在c ++中編譯但在c(gcc)中編譯時復雜

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM