简体   繁体   English

是否适合在头文件中将值设置为“const char *”

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

I have seen people using 2 methods to declare and define char * . 我见过人们使用2种方法来声明和定义char *

Medhod 1: The header file has the below Medhod 1:头文件如下

extern const char* COUNTRY_NAME_USA = "USA";

Medhod 2: Medhod 2:
The header file has the below declaration: 头文件具有以下声明:

extern const char* COUNTRY_NAME_USA;

The cpp file has the below definition: cpp文件具有以下定义:

extern const char* COUNTRY_NAME_USA = "USA";
  1. Is method 1 wrong in some way ? 方法1在某种程度上是错误的吗?
  2. What is the difference between the two ? 两者有什么区别 ?
  3. I understand the difference between " const char * const var " , and " const char * var ". 我理解“ const char * const var ”和“ const char * var ”之间的区别。 If in the above methods if a " const char * const var " is declared and defined in the header as in method 1 will it make sense ? 如果在上面的方法中,如果在方法1中声明并定义了标头中的“ const char * const var ”,那么它是否有意义?

The first method is indeed wrong, since it makes a definition of an object COUNTRY_NAME_USA with external linkage in the header file. 第一种方法确实是错误的,因为它在头文件中定义了具有外部链接的对象COUNTRY_NAME_USA Once that header file gets included into more than one translation unit, the One Definition Rule (ODR) gets violated. 一旦该头文件被包含到多个翻译单元中,就会违反一个定义规则(ODR)。 The code will fail to compile (more precisely, it will fail to link). 代码将无法编译(更确切地说,它将无法链接)。

The second method is the correct one. 第二种方法是正确的。 The keyword extern is optional in the definition though, ie in the cpp file you can just do 关键字extern在定义中是可选的,即在cpp文件中你可以做

const char* COUNTRY_NAME_USA = "USA"

assuming the declaration from the header file precedes this definition in this translation unit. 假设头文件中的声明在此翻译单元中位于此定义之前。

Also, I'd guess that since the object name is capitalized, it is probably intended to be a constant . 此外,我猜测,因为对象名称是大写的,它可能是一个常量 If so, then it should be declared/defined as const char* const COUNTRY_NAME_USA (note the extra const ). 如果是这样,那么它应该声明/定义为const char* const COUNTRY_NAME_USA (注意额外的const )。

Finally, taking that last detail into account, you can just define your constant as 最后,考虑到最后一个细节,您可以将常量定义为

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

in the header file. 在头文件中。 Since it is a constant now, it has internal linkage by default, meaning that there is no ODR violation even if the header file is included into several translation units. 由于它现在是常量,因此默认情况下它具有内部链接,这意味着即使头文件包含在多个转换单元中也不存在ODR违规。 In this case you get a separate COUNTRY_NAME_USA lvalue in each translation unit (while in extern method you get one for the entire program). 在这种情况下,您会在每个翻译单元中获得单独的COUNTRY_NAME_USA左值(而在extern方法中,您将获得整个程序的左值)。 Only you know what you need in your case . 只有你知道你需要什么。

What's the point? 重点是什么?

If you want to lookup strings (that could be localized), this would be best: 如果你想查找字符串(可以本地化),这将是最好的:

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

Since the pointer is const, it now has internal linkage and won't cause multiple definitions. 由于指针是const,它现在具有内部链接,不会导致多个定义。 Most linkers will also combine redundant constants, so you won't waste space in the executable. 大多数链接器也会组合冗余常量,因此您不会在可执行文件中浪费空间。

If you want to compare strings by pointer equality though, the above isn't portable because the pointers will only be equal if the linker performs the constant-folding optimization. 如果你想通过指针相等来比较字符串,上面的内容是不可移植的,因为如果链接器执行常量折叠优化,指针只会相等。 In that case declaring an extern pointer in the header file is the way to go (and it again should be const if you don't intend to retarget it). 在这种情况下,在头文件中声明一个extern指针是要走的路(如果你不打算重新定位它,它也应该是const)。

If you must have global variables, normal practice is to declare them in a .h file and define them in one (and only one) .cpp file. 如果必须有全局变量,通常的做法是在.h文件中声明它们并在一个(且只有一个).cpp文件中定义它们。

In a .h file; 在.h文件中;

extern int x;

In a .cpp file; 在.cpp文件中;

int x=3;

I have used int (the most fundamental basic type perhaps?) rather than const char * as in your example because the essence of your problem doesn't depend on the type of variable. 我在你的例子中使用了int(最基本的基本类型?)而不是const char *,因为问题的本质不依赖于变量的类型。

The basic idea is that you can declare a variable multiple times, so each .cpp file that includes the .h file declares the variable, and that is fine. 基本的想法是你可以多次声明一个变量,所以包含.h文件的每个.cpp文件都会声明变量,这很好。 But you only define it once. 但是你只定义一次。 The definition is the statement where you assign the variables initial value, (with an =). 定义是指定变量初始值的语句(带有=)。 You don't want definitions in .h files, because then if the .h file is included by multiple .cpp files, you'll get multiple definitions. 您不希望在.h文件中定义,因为如果多个.cpp文件包含.h文件,您将获得多个定义。 If you have multiple definitions of one variable, there is a problem at link time because the linker wants to assign the address of the variable and cannot reasonably do that if there are multiple copies of it. 如果您对一个变量有多个定义,则链接时会出现问题,因为链接器想要分配变量的地址,如果有多个副本,则无法合理地执行此操作。

Additional information added later to try and ease Sud's confusion; 后来添加的其他信息试图缓解Sud的混乱;

Try to reduce your problem to it's minimal parts to understand it better; 尝试将问题减少到最小的部分,以便更好地理解它;

Imagine you have a program that comprises three .cpp files. 想象一下,你有一个包含三个.cpp文件的程序。 To build the program each .cpp is compiled separately to create three object files, then the three object files are linked together. 为了构建程序,每个.cpp被单独编译以创建三个目标文件,然后将三个目标文件链接在一起。 If the three .cpp files are as follows (example A, good organization); 如果三个.cpp文件如下(例A,良好的组织);

file1.cpp file1.cpp

extern int x;

file2.cpp file2.cpp

extern int x;

file3.cpp file3.cpp

extern int x;

Then the files will compile and link together without problem (at least as far as the variable x is concerned). 然后文件将编译并链接在一起没有问题(至少就变量x而言)。 There is no problem because each file is only declaring variable x. 没有问题,因为每个文件只声明变量x。 A declaration is simply stating that there is a variable out there somewhere that I may (or may not) use. 声明只是声明我可能(或可能不)使用某个地方的变量。

A better way of achieving the same thing is the following (example A, better organization); 实现同样目标的更好方法是以下(示例A,更好的组织);

header.h header.h

extern int x;

file1.cpp file1.cpp

#include "header.h"

file2.cpp file2.cpp

#include "header.h"

file3.cpp file3.cpp

#include "header.h"

This is effectively exactly the same, for each of the three compilations the compiler sees the same text as earlier as it processes the .cpp file (or translation unit as the experts call it), because the #include directive simply pulls text from another file. 这实际上是完全相同的,对于三个编译中的每一个,编译器看到与之前处理.cpp文件(或专家称之为翻译单元)的文本相同的文本,因为#include指令只是从另一个文件中提取文本。 Nevertheless this is an improvement on the earlier example simply because we only have our declaration in one file, not in multiple files. 然而,这是对前面示例的改进,因为我们只将声明放在一个文件中,而不是放在多个文件中。

Now consider another working example (example B, good organization); 现在考虑另一个工作示例(例子B,良好的组织);

file1.cpp file1.cpp

extern int x;

file2.cpp file2.cpp

extern int x;

file3.cpp file3.cpp

extern int x;
int x=3;

This will work fine as well. 这也可以。 All three .cpp files declare x and one actually defines it. 所有三个.cpp文件都声明x,一个实际定义它。 We could go ahead and add more code within functions in any of the three files that manipulates variable x and we wouldn't get any errors. 我们可以继续在操作变量x的三个文件中的任何一个函数中添加更多代码,我们不会得到任何错误。 Again we should use a header file so that the declaration only goes into one physical file (example B, better organization). 我们应该再次使用头文件,以便声明只进入一个物理文件(例子B,更好的组织)。

header.h header.h

extern int x;

file1.cpp file1.cpp

#include "header.h"

file2.cpp file2.cpp

#include "header.h"

file3.cpp file3.cpp

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

Finally consider an example that just wouldn't work (example C, doesn't work); 最后考虑一个不起作用的例子(例子C,不起作用);

file1.cpp file1.cpp

int x=3;

file2.cpp file2.cpp

int x=3;

file3.cpp file3.cpp

int x=3;

Each file would compile without problems. 每个文件都会编译没有问题。 The problem occurs at link time because now we have defined three separate int x variables. 问题出现在链接时,因为现在我们已经定义了三个独立的int x变量。 The have the same name and are all globally visible. 它们具有相同的名称,并且全局可见。 The linker's job is to pull all the objects required for a single program into one executable. 链接器的工作是将单个程序所需的所有对象拉入一个可执行文件中。 Globally visible objects must have a unique name, so that the linker can put a single copy of the object at one defined address (place) in the executable and allow all the other objects to access it at that address. 全局可见对象必须具有唯一名称,以便链接器可以将对象的单个副本放在可执行文件中的一个已定义地址(位置),并允许所有其他对象在该地址访问它。 The linker cannot do it's job with global variable x in this case and so will choke out an error instead. 在这种情况下,链接器无法使用全局变量x来完成它的工作,因此会阻塞错误。

As an aside giving the different definitions different initial values doesn't address the problem. 另外,给出不同的定义,不同的初始值不能解决问题。 Preceding each definition with the keyword static does address the problem because now the variables are not globally visible, but rather visible within the .cpp file that the are defined in. 使用关键字static在每个定义之前确实解决了问题,因为现在变量不是全局可见的,而是在定义的.cpp文件中可见。

If you put a global variable definition into a header file, nothing essential has changed (example C, header organization not helpful in this case); 如果将全局变量定义放入头文件中,则没有任何必要的更改(例如,在这种情况下,标题组织没有帮助);

header.h header.h

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

file1.cpp file1.cpp

#include "header.h"

file2.cpp file2.cpp

#include "header.h"

file3.cpp file3.cpp

#include "header.h"

Phew, I hope someone reads this and gets some benefit from it. Phew,我希望有人读到这个并从中获益。 Sometimes the questioner is crying out for a simple explanation in terms of basic concepts not an advanced computer scientist's explanation. 有时,提问者急切地想要根据基本概念进行简单的解释,而不是先进的计算机科学家的解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM