Where to define a const string?

R

Riley DeWiley

I am looking for a graceful way to declare a string const that is to be
visible across many files.

If I do this:

//----hdr.h

const char * sFoo = "foo";

//file.cpp
#include <hdr.h>

strcpy(string, sFoo);


//anotherfile.cpp
#include <hdr.h>

strcpy(string, sFoo);


The linker complains that sFoo is multiply defined.

I don't want to use a #define as it breaks type safety. I don't want to have
multiple copies of '
const char * sFoo = "foo";' littering my code.

What is the most compact and maintainable way to do this?

RDeW
 
B

Bryan Donlan

Riley said:
I am looking for a graceful way to declare a string const that is to be
visible across many files.

If I do this:
[snip example]

The linker complains that sFoo is multiply defined.

I don't want to use a #define as it breaks type safety. I don't want to
have multiple copies of '
const char * sFoo = "foo";' littering my code.

What is the most compact and maintainable way to do this?

RDeW

Header file:
extern const char sFoo[];

In (one) source file (exactly which doesn't matter):
const char sFoo[] = "foo";
 
V

Victor Bazarov

Riley said:
I am looking for a graceful way to declare a string const that is to be
visible across many files.

If I do this:

//----hdr.h

const char * sFoo = "foo";

//file.cpp
#include <hdr.h>

strcpy(string, sFoo);


//anotherfile.cpp
#include <hdr.h>

strcpy(string, sFoo);


The linker complains that sFoo is multiply defined.

I don't want to use a #define as it breaks type safety. I don't want to have
multiple copies of '
const char * sFoo = "foo";' littering my code.

What is the most compact and maintainable way to do this?

If you declare it in the header

const char * const sFoo = "foo";

which creates multiple copies. To avoid that you could do

extern const char sFoo[];

in the header and in _one_of_the_C++_source_files_ do

extern const char sFoo[] = "foo";

The linker will be happy and you will have the only definition of the
string in the program.

V
 
P

Pete Becker

Riley said:
I don't want to use a #define as it breaks type safety.

No, it doesn't.

#define sFoo "foo"

Every place you use the identifier sFoo you'll get a string literal. Its
type, however, is array of const char rather than pointer to const char,
which is what your code uses.
I don't want to have
multiple copies of '
const char * sFoo = "foo";' littering my code.

What is the most compact and maintainable way to do this?

In the header:
const char *sFoo;

In one implementation file:
const char *sFoo = "foo";

The suggestion the other messages make, to use const char sFoo[], also
works, but just like the macro, it makes sFoo a different type from what
you asked for.
 
B

Bryan Donlan

Pete said:
No, it doesn't.

#define sFoo "foo"

Every place you use the identifier sFoo you'll get a string literal. Its
type, however, is array of const char rather than pointer to const char,
which is what your code uses.


In the header:
const char *sFoo;

In one implementation file:
const char *sFoo = "foo";

This is wrong. The first will create a pointer, initialized to NULL, in each
file it's included in. The second will create yet another pointer,
initialized to pointing to the constant string needed.
The suggestion the other messages make, to use const char sFoo[], also
works, but just like the macro, it makes sFoo a different type from what
you asked for.

The array will automatically cast into const char * when needed, so it
doesn't matter.
 
G

Greg

Victor said:
Riley said:
I am looking for a graceful way to declare a string const that is to be
visible across many files.

If I do this:

//----hdr.h

const char * sFoo = "foo";

//file.cpp
#include <hdr.h>

strcpy(string, sFoo);


//anotherfile.cpp
#include <hdr.h>

strcpy(string, sFoo);


The linker complains that sFoo is multiply defined.

I don't want to use a #define as it breaks type safety. I don't want to have
multiple copies of '
const char * sFoo = "foo";' littering my code.

What is the most compact and maintainable way to do this?

If you declare it in the header

const char * const sFoo = "foo";

which creates multiple copies. To avoid that you could do

extern const char sFoo[];

in the header and in _one_of_the_C++_source_files_ do

extern const char sFoo[] = "foo";

The linker will be happy and you will have the only definition of the
string in the program.

V

Const declarations by default have internal linkage, so the declaration
can remain in the header file once it's changed from a pointer to an
array. No source files need to be changed.

In other words change this declaration in the header file:

const char * const sFoo = "foo";

to this:

const char const sFoo[] = "foo";

And the multiple definition error will be fixed - no matter how many
source files actually include sFoo's declaration.

Greg
 
P

Pete Becker

Bryan said:
Pete Becker wrote:




This is wrong. The first will create a pointer, initialized to NULL, in each
file it's included in.

You're right: it needs an extern in front.
The suggestion the other messages make, to use const char sFoo[], also
works, but just like the macro, it makes sFoo a different type from what
you asked for.


The array will automatically cast into const char * when needed, so it
doesn't matter.

First, a cast is something you write in your code to tell the compiler
that you want a conversion. Second, there are two contexts in which the
conversion from array into pointer to its first element is not done. The
two types are not the same.
 
P

Pete Becker

Pete said:
Second, there are two contexts in which the
conversion from array into pointer to its first element is not done. The
two types are not the same.

Actually, that's true in C. In C++ there are more. And, in both
languages, this is not a conversion, but a decay: the name of an array
decays into a pointer to its first element in most contexts. And, of
course, it is still true that the two types are not the same. Try this:

a.c
---
char text[] = "abcd";

void f()
{
puts(text);
}

b.c
---
extern char *text;
void f();

int main()
{
*text = 'e';
f();
return 0;
}
 
M

Marcus Kwok

Riley DeWiley said:
I am looking for a graceful way to declare a string const that is to be
visible across many files.

If I do this:

//----hdr.h

const char * sFoo = "foo";

//file.cpp
#include <hdr.h>

strcpy(string, sFoo);


//anotherfile.cpp
#include <hdr.h>

strcpy(string, sFoo);


The linker complains that sFoo is multiply defined.

I don't want to use a #define as it breaks type safety. I don't want to have
multiple copies of '
const char * sFoo = "foo";' littering my code.

What is the most compact and maintainable way to do this?

Would an #include guard work?


//-----hdr.h
#ifndef HDR_H
#define HDR_H

const char* sFoo = "foo";

#endif
 
?

=?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunino?=

Riley DeWiley said:
I am looking for a graceful way to declare a string const that is to be
visible across many files.
[...]
What is the most compact and maintainable way to do this?

Probably not the most compact way, but I suppose it would fit into the
maintainable and correct categories.


//--- MagicString.h

#ifndef MAGIC_STRING_H__
#define MAGIC_STRING_H__

extern const char* const gMagicString;

#endif


//--- MagicString.cpp

#include "MagicString.h"

const char* const gMagicString = "I am a magic string!";


//--- test.cpp

#include "MagicString.h"
#include <iostream>

int main()
{
std::cout << gMagicString << '\n';
}


Regards,
 
M

Marcelo Pinto

Just a reminder on your include guards: words with double underscores
are reserved for the implemention.
 
K

Kai-Uwe Bux

Markus said:
... at the beginning ...

Nope: double underscores are off limits regardless of their position within
identifiers. See [17.4.3.1.2/1]:

17.4.3.1.2 Global names [lib.global.names]

1 Certain sets of names and function signatures are always reserved
to the implementation:

? Each name that contains a double underscore (__) or begins with
an underscore followed by an uppercase letter (2.11) is reserved
to the implementation for any use.



Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top