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

牧云@^-^@ 提交于 2019-12-03 11:37:59

问题


I have seen people using 2 methods to declare and define char *.

Medhod 1: The header file has the below

extern const char* COUNTRY_NAME_USA = "USA";

Medhod 2:
The header file has the below declaration:

extern const char* COUNTRY_NAME_USA;

The cpp file has the below definition:

extern const char* COUNTRY_NAME_USA = "USA";
  1. Is method 1 wrong in some way ?
  2. What is the difference between the two ?
  3. I understand the difference between "const char * const var" , and "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:


The first method is indeed wrong, since it makes a definition of an object COUNTRY_NAME_USA with external linkage in the header file. Once that header file gets included into more than one translation unit, the One Definition Rule (ODR) gets violated. 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, i.e. in the cpp file you can just do

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).

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. 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). Only you know what you need in your case .




回答2:


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. 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).




回答3:


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.

In a .h file;

extern int x;

In a .cpp file;

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.

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. 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. 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;

Try to reduce your problem to it's minimal parts to understand it better;

Imagine you have a program that comprises three .cpp files. To build the program each .cpp is compiled separately to create three object files, then the three object files are linked together. If the three .cpp files are as follows (example A, good organization);

file1.cpp

extern int x;

file2.cpp

extern int x;

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). There is no problem because each file is only declaring variable 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);

header.h

extern int x;

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

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. 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);

file1.cpp

extern int x;

file2.cpp

extern int x;

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. 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. Again we should use a header file so that the declaration only goes into one physical file (example B, better organization).

header.h

extern int x;

file1.cpp

#include "header.h"

file2.cpp

#include "header.h"

file3.cpp

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

Finally consider an example that just wouldn't work (example C, doesn't work);

file1.cpp

int x=3;

file2.cpp

int x=3;

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. 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.

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.

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

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, I hope someone reads this and gets some benefit from it. Sometimes the questioner is crying out for a simple explanation in terms of basic concepts not an advanced computer scientist's explanation.



来源:https://stackoverflow.com/questions/2879548/is-it-appropriate-to-set-a-value-to-a-const-char-in-the-header-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!