Home > front end >  C17 how to declare and define global const string
C17 how to declare and define global const string

Time:10-05

I have to use a globally const string in C (we are using C 17 as a standard) Since we run this application on an embedded target, I'd want that my string is not copied into every translation unit

I know of 3 ways, but I'm not sure which way to use.

Option 1

header.h

#pragma once
extern const char* pString;

source.c

#include "header.h"
const char* pString = "Foo";

Option 2

(this does not work on all compilers though)

header.h

#pragma once
extern const char string[];

source.c

#include "header.h"
const char string[] = "Foo"

Option 3

(only define string in header)

header.h

#pragma once
const char string[] = "Foo";

How would you declare a global const string in C?

CodePudding user response:

First of all #pragma once is non-portable. Unless you like to write non-portable code just for the heck of it, you should replace it with normal standard header guards. #ifndef HEADER_H ... #define HEADER_H ... #endif. If you simply must use non-standard features or you'll start sneezing, then keep #pragma once...

Also, sharing string literals across multiple files by using global variables is bad practice. Not as bad practice as sharing read/write global variables, but still bad and an indication of poorly considered design.


Option 1

Fine if you want the pointer to be allocated in RAM, wrong if you want to allocate it in flash. In case of flash allocation, you need to do:

const char* const pString = "Foo";

Option 2
(this does not work on all compilers though)

It sure does work on all conforming C compilers. It may not work on some C compilers because string is a very bad choice for name. Go with str.

Please note that the Option 2 version does not allocate a separate pointer but refers directly to the string literal (which is in turn located in .rodata or maybe `.text).

(Some semi-exotic micocontrollers may not be able to access string literals in such memory directly, because they are some flavour of Harvad architecture, or because they might use page/bank memory etc etc. But that's no concern for standard C.)


Option 3

Don't do that, it will only cause linker problems in case multiple translation units try to declare the variable independently of each other. It's also poor design.


Option 4

#define str "string literal"

This means that the string won't necessarily get a fixed/known memory location, but the compiler will store it where it pleases. Might be ever so slightly more efficient in terms of string pooling and similar, but it's also questionable design for the same global variable reason as mentioned earlier.


Option 5

// foo.h
const char* get_str (void);

// foo.c
const char* get_str (void)
{
  return "foo";
}

This is good design with a setter/getter and information encapsulation. The down side is that this won't necessarily be inlined across multiple translation units, so there may be a slight overhead.

(You could make it static inline and place in a header, but then it's back to square 1 with the global spaghetti.)


Options 1, 2, 4 and 5 are all viable and which one to use depends on the context.

  • Related