簡體   English   中英

是否適合在頭文件中將值設置為“const char *”

[英]Is it appropriate to set a value to a “const char *” in the header file

我見過人們使用2種方法來聲明和定義char *

Medhod 1:頭文件如下

extern const char* COUNTRY_NAME_USA = "USA";

Medhod 2:
頭文件具有以下聲明:

extern const char* COUNTRY_NAME_USA;

cpp文件具有以下定義:

extern const char* COUNTRY_NAME_USA = "USA";
  1. 方法1在某種程度上是錯誤的嗎?
  2. 兩者有什么區別 ?
  3. 我理解“ const char * const var ”和“ const char * var ”之間的區別。 如果在上面的方法中,如果在方法1中聲明並定義了標頭中的“ const char * const var ”,那么它是否有意義?

第一種方法確實是錯誤的,因為它在頭文件中定義了具有外部鏈接的對象COUNTRY_NAME_USA 一旦該頭文件被包含到多個翻譯單元中,就會違反一個定義規則(ODR)。 代碼將無法編譯(更確切地說,它將無法鏈接)。

第二種方法是正確的。 關鍵字extern在定義中是可選的,即在cpp文件中你可以做

const char* COUNTRY_NAME_USA = "USA"

假設頭文件中的聲明在此翻譯單元中位於此定義之前。

此外,我猜測,因為對象名稱是大寫的,它可能是一個常量 如果是這樣,那么它應該聲明/定義為const char* const COUNTRY_NAME_USA (注意額外的const )。

最后,考慮到最后一個細節,您可以將常量定義為

const char* const COUNTRY_NAME_USA = "USA"; // no `extern`!

在頭文件中。 由於它現在是常量,因此默認情況下它具有內部鏈接,這意味着即使頭文件包含在多個轉換單元中也不存在ODR違規。 在這種情況下,您會在每個翻譯單元中獲得單獨的COUNTRY_NAME_USA左值(而在extern方法中,您將獲得整個程序的左值)。 只有你知道你需要什么。

重點是什么?

如果你想查找字符串(可以本地化),這將是最好的:

namespace CountryNames {
    const char* const US = "USA";
};

由於指針是const,它現在具有內部鏈接,不會導致多個定義。 大多數鏈接器也會組合冗余常量,因此您不會在可執行文件中浪費空間。

如果你想通過指針相等來比較字符串,上面的內容是不可移植的,因為如果鏈接器執行常量折疊優化,指針只會相等。 在這種情況下,在頭文件中聲明一個extern指針是要走的路(如果你不打算重新定位它,它也應該是const)。

如果必須有全局變量,通常的做法是在.h文件中聲明它們並在一個(且只有一個).cpp文件中定義它們。

在.h文件中;

extern int x;

在.cpp文件中;

int x=3;

我在你的例子中使用了int(最基本的基本類型?)而不是const char *,因為問題的本質不依賴於變量的類型。

基本的想法是你可以多次聲明一個變量,所以包含.h文件的每個.cpp文件都會聲明變量,這很好。 但是你只定義一次。 定義是指定變量初始值的語句(帶有=)。 您不希望在.h文件中定義,因為如果多個.cpp文件包含.h文件,您將獲得多個定義。 如果您對一個變量有多個定義,則鏈接時會出現問題,因為鏈接器想要分配變量的地址,如果有多個副本,則無法合理地執行此操作。

后來添加的其他信息試圖緩解Sud的混亂;

嘗試將問題減少到最小的部分,以便更好地理解它;

想象一下,你有一個包含三個.cpp文件的程序。 為了構建程序,每個.cpp被單獨編譯以創建三個目標文件,然后將三個目標文件鏈接在一起。 如果三個.cpp文件如下(例A,良好的組織);

file1.cpp

extern int x;

file2.cpp

extern int x;

file3.cpp

extern int x;

然后文件將編譯並鏈接在一起沒有問題(至少就變量x而言)。 沒有問題,因為每個文件只聲明變量x。 聲明只是聲明我可能(或可能不)使用某個地方的變量。

實現同樣目標的更好方法是以下(示例A,更好的組織);

header.h

extern int x;

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

#include "header.h"

這實際上是完全相同的,對於三個編譯中的每一個,編譯器看到與之前處理.cpp文件(或專家稱之為翻譯單元)的文本相同的文本,因為#include指令只是從另一個文件中提取文本。 然而,這是對前面示例的改進,因為我們只將聲明放在一個文件中,而不是放在多個文件中。

現在考慮另一個工作示例(例子B,良好的組織);

file1.cpp

extern int x;

file2.cpp

extern int x;

file3.cpp

extern int x;
int x=3;

這也可以。 所有三個.cpp文件都聲明x,一個實際定義它。 我們可以繼續在操作變量x的三個文件中的任何一個函數中添加更多代碼,我們不會得到任何錯誤。 我們應該再次使用頭文件,以便聲明只進入一個物理文件(例子B,更好的組織)。

header.h

extern int x;

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

#include "header.h"
int x=3;

最后考慮一個不起作用的例子(例子C,不起作用);

file1.cpp

int x=3;

file2.cpp

int x=3;

file3.cpp

int x=3;

每個文件都會編譯沒有問題。 問題出現在鏈接時,因為現在我們已經定義了三個獨立的int x變量。 它們具有相同的名稱,並且全局可見。 鏈接器的工作是將單個程序所需的所有對象拉入一個可執行文件中。 全局可見對象必須具有唯一名稱,以便鏈接器可以將對象的單個副本放在可執行文件中的一個已定義地址(位置),並允許所有其他對象在該地址訪問它。 在這種情況下,鏈接器無法使用全局變量x來完成它的工作,因此會阻塞錯誤。

另外,給出不同的定義,不同的初始值不能解決問題。 使用關鍵字static在每個定義之前確實解決了問題,因為現在變量不是全局可見的,而是在定義的.cpp文件中可見。

如果將全局變量定義放入頭文件中,則沒有任何必要的更改(例如,在這種情況下,標題組織沒有幫助);

header.h

int x=3;  // Don't put this in a .h file, causes multiple definition link error

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

#include "header.h"

Phew,我希望有人讀到這個並從中獲益。 有時,提問者急切地想要根據基本概念進行簡單的解釋,而不是先進的計算機科學家的解釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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