C - initialize wchar_t array within global struct

91 Views Asked by At

My goal is to have a default_game_data.h and a default_game_data.c where I can store, for example, some default weapon data to load, when the player changes weapons.

default_game_data.h:

typedef struct weapon
{
    wchar_t name[30];
    int  damage;
    int  agility_modify;
}weapon;


const extern weapon sword;

default_game_data.c:

#include "default_game_data.h"

const weapon sword = {
    .name = {L'S',L'w',L'o',L'r',L'd',L'\0'},
    .agility_modify = 0,
    .damage = 5
};

This is the only way I could compile without this error:

integer conversion resulted in truncation
C/C++(69) 
 wchar_t [10]{(error-type)error-constant}

But initializing the array wchar-by-wchar is pretty annoying to maintain, and as soon as I try like .name = L"Sword", I got this error above.

Does anyone know how to assign a wchar_t[] the same way like a char[]? Or, maybe there is a better method of storing such data? It should be central and editable.

For a short experiment, I try a char[] and wchar_t[] example:

typedef struct c_human {
    char f_name[10];
    char *s_name;
}c_human;

c_human human1 = {
    .f_name = "Peter",
    .s_name = "Hagen"
};

typedef struct w_human {
    wchar_t f_name[10];
    wchar_t *s_name;
}w_human;

w_human human2 = {
    .f_name = L"Peter",
    .s_name = L"Hagen"
};

w_human human3 = {
    .f_name = {L'P',L'e',L't',L'e',L'r',L'\0'},
    .s_name = L"Hagen"
};

Assigning .s_name via pointer always works out, but I think it overflows the storage beyond.

Assigning human1.f_name works with = "Peter", but assigning human2.f_name with = L"Peter" does not.

1

There are 1 best solutions below

2
John Bollinger On

Does anyone knows how to assign a wchar_t[] the same way like a char[]?

It's important to distinguish between assigning and initializing. Your examples deal with the latter, not the former, and the rules for these are not the same. In particular, you cannot assign to whole arrays at all.

But you can initialize wchar_t arrays with wide string literals, in every version of standard C. C23 puts it this way:

An array with element type compatible with a qualified or unqualified version of wchar_t, char16_t, or char32_t may be initialized by a wide string literal with the corresponding encoding prefix (L, u, or U, respectively), optionally enclosed in braces. Successive wide characters of the wide string literal (including the terminating null wide character if there is room or if the array is of unknown size) initialize the elements of the array.

(C23 6.7.10/16)

That's closely analogous to the provisions for initializing a char[] with an ordinary string literal. In particular, this:

const weapon sword = {
    .name = L"Sword",
    .agility_modify = 0,
    .damage = 5
};

and this:

const weapon sword = {
    .name = { L"Sword" },
    .agility_modify = 0,
    .damage = 5
};

conform to every version of C from C89 through C23, given the definition of weapon provided in the question. And my compiler (GCC 8.5.0) accepts both without any complaint.


With respect to your second set of examples, you say

Assigning .s_name via pointer always works out, but I think it overflows the storage beyond.

I see no reason to think that that would overflow in any of the cases presented.

And I see no reason to expect that a conforming C compiler would reject ...

w_human human2 = {
    .f_name = L"Peter",
    .s_name = L"Hagen"
};

If your compiler is rejecting that (in the context of the given definition for w_human), then I would attribute that to a compiler bug.