Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define string array

I would like to define an array of string like that:

#define sup (const char**) ("string1", "string2")

but it fails when I try to print the first string:

printf("The string: %s\n",sup[0]); 

how to do it in the proper way?

like image 986
Beppe Avatar asked Feb 26 '23 01:02

Beppe


2 Answers

I would advice against doing this with macros altogether, but if you are really interested in what is going on with the code --more than in how this should actually be tackled, here is an explanation.

There is a simple issue in the code, and a more obscure one. The very simple is that to declare an array you don't use parenthesis but rather curly braces:

#define sup (const char**){"str1", "str2"} // still wrong!!

The less simple issue is that arrays are not pointers. The curly brace initializer can be used to initialize an array of two const char*, but that is not the same as a const char**. If you change the code to:

#define sup (const char*[2]){"str1", "str2" }

It should work.

What is going on under the hood with the previous version? Well, the compiler is seeing the declaration of a pointer (well, casting to a pointer) and the initializer. It is assuming that you want to initialize the pointer with the first element (incompatible pointer, but the cast is explicit... you must know what you want if you forced the cast), and then ignore the remainder. Basically the compiler translates your code to [*]:

#define sup (const char**)"str1"

And that will cause havoc at runtime. It is interesting to note that if you had used a proper variable and then initialized the pointer with it, it would have worked, because while arrays are not pointers (I insist, keep that in mind) arrays do decay into pointers:

const char* tmp[] = { "hi", "there" };
const char** sup = tmp;              // fine, tmp decays into &tmp[0]

[*] There's a bit of handwaving there... the compiler translates the code, once inserted at the place of use of the macro by the preprocessor, but the translation is equivalent to what I wrote if you were to edit the macro manually.

like image 182
David Rodríguez - dribeas Avatar answered Mar 01 '23 11:03

David Rodríguez - dribeas


I think that doing this kind of preprocessor tricks, especially with arrays, isn't such a good idea. You should instead have a real global string table, like this:

const char const * sup[]={"String 1", "String 2", "String 3"};

in one of the .c files, and put its extern declaration in a header to be included wherever such strings are needed:

extern const char const * sup[];

(the first const is to avoid modifications to each string literal - which is UB -, the second to avoid replacing the pointers stored in sup; if you want to allow this last action, remove the second const)

An alternative approach would be to define sup directly in the header as a static global variable (i.e. with internal linkage); I've seen this done before with integer constants to make sure they are immediately known to the compiler in every translation unit (so it can put them as immediate values in the generated assembly), but I don't think that with string pointers it can give any significant performance boost.

like image 34
Matteo Italia Avatar answered Mar 01 '23 09:03

Matteo Italia