Where to define a const string?

  • Follow


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 


0
Reply riley.dewiley (26) 8/26/2005 7:34:53 PM

Riley DeWiley wrote:

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

-- 
λz.λi.i(i((λn.λm.λz.λi.nz(λq.mqi))((λn.λz.λi.n(nzi)i)(λz.λi.i(((λn.λz.λi.n
(nzi)i)(λz.λi.i(iz)))zi)))((λn.λz.λi.n(nzi)i)(λz.λi.i(iz)))zi))
0
Reply bdonlan2 (53) 8/26/2005 7:39:53 PM


Riley DeWiley wrote:
> 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
0
Reply v.Abazarov (13255) 8/26/2005 7:46:19 PM

Riley DeWiley wrote:
> 
> 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.

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
0
Reply petebecker (1324) 8/26/2005 8:14:59 PM

Pete Becker wrote:

> Riley DeWiley wrote:
>> 
>> 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";

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.

-- 
λz.λi.i(i((λn.λm.λz.λi.nz(λq.mqi))((λn.λz.λi.n(nzi)i)(λz.λi.i(((λn.λz.λi.n
(nzi)i)(λz.λi.i(iz)))zi)))((λn.λz.λi.n(nzi)i)(λz.λi.i(iz)))zi))
0
Reply bdonlan2 (53) 8/26/2005 11:26:33 PM

Victor Bazarov wrote:
> Riley DeWiley wrote:
> > 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

0
Reply greghe (676) 8/27/2005 6:08:50 AM

Bryan Donlan wrote:
> Pete Becker wrote:
> 
> 
>>
>>>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";
> 
> 
> 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.

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
0
Reply petebecker (1324) 8/27/2005 6:30:08 PM

Pete Becker wrote:
> 
> 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;
   }

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
0
Reply petebecker (1324) 8/27/2005 8:29:13 PM

Riley DeWiley <riley.dewiley@gmail.com> wrote:
> 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

-- 
Marcus Kwok
0
Reply ricecake (206) 9/20/2005 3:49:33 PM

Riley DeWiley <riley.dewiley@gmail.com> wrote:

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

-- 
Ney Andr� de Mello Zunino
0
Reply zunino2 (84) 9/20/2005 7:35:04 PM

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

0
Reply mpinto70 (54) 9/20/2005 8:46:18 PM

Marcelo Pinto <mpinto70@gmail.com> schrieb:
> Just a reminder on your include guards: words with double underscores

.... at the beginning ...

> are reserved for the implemention.

Regards, Markus
0
Reply yetispamb (62) 9/25/2005 2:10:34 PM

Markus Becker wrote:

> Marcelo Pinto <mpinto70@gmail.com> schrieb:
>> Just a reminder on your include guards: words with double underscores
> 
> ... 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.


>> are reserved for the implemention.


Best

Kai-Uwe Bux

0
Reply jkherciueh (3186) 9/25/2005 2:28:20 PM

12 Replies
21 Views

(page loaded in 0.273 seconds)


Reply: