Как переписать назначенные инициализаторы C-структуры на C89 (например, компилятор MSVC C)
Ребята, у меня есть эта проблема:
Обычно в C99 GCC (cygwin/MinGW/linux) существует синтаксис точечной нотации для инициализаторов в C struct.
Вот так:
//HELP ME HOW TO REWRITE THIS (in most compact way) to MSVC
static struct my_member_t my_global_three[] = {
{.type = NULL, .name = "one"},
{.type = NULL, .name = "two"},
{.type = NULL, .name = "three"},
};
Имея my_memeber_t
, определенный в файле заголовка как:
struct my_member_t {
struct complex_type * type;
char * name;
int default_number;
void * opaque;
};
Я компилирую код Linux в MSVC 9.0 (Visual Studio 2008), на cygwin/MinGW это работает нормально.
BUT cl не может скомпилировать это (из-за несчастной реализации C99): error C2059: syntax error : '.'
PROBLEM:
How to rewrite (many) global structs in a way that MSVC
(resp C89)
can compile it?
С наилучшими пожеланиями и благодарностью за предложения...
Ответы
Ответ 1
Несчастная реализация C99? Я не думаю, что компилятор C в VC2008 даже пытается реализовать C99. Он может занять некоторые функции, но это действительно компилятор C89/90.
Просто отбросьте теги имен полей
static struct my_member_t my_global_three[] = {
{ NULL, "one"},
{ NULL, "two"},
{ NULL, "three"},
};
В этом случае это легко, так как порядок инициализаторов в исходном коде совпадает с порядком полей в структуре. Если порядок отличается, вам придется переставить их в версии без тегов C89/90.
И если это действительно ваш my_member_t
, тогда вы должны либо объявить строковый указатель как const char *
, либо прекратить инициализацию этих элементов строковыми литералами.
Ответ 2
Спасибо за вашу информацию, Нико.
Однако я обнаружил, что для структур с массивами внутри не работает. Я предлагаю эту модификацию, которая работает как для C99, так и для MSVC (проверена в MSVС++ 2010 Express):
#ifdef HAVE_DESIGNATED_INITIALIZERS
#define SFINIT(f, ...) f = __VA_ARGS__
#else
#define SFINIT(f, ...) __VA_ARGS__
#endif
typedef struct {
int val;
int vecB[4];
int vecA[4];
} MyStruct_ts;
static const MyStruct_ts SampleStruct =
{
SFINIT(.val , 8),
SFINIT(.vecB , { 1, -2, 4, -2}),
SFINIT(.vecA , { 1, -3, 5, -3}),
};
Таким образом, вы можете использовать один файл для MSVC и других компиляторов.
Ответ 3
/*
* Macro for C99 designated initializer -> C89/90 non-designated initializer
*
* Tested. Works with MSVC if you undefine HAVE_DESIGNATED_INITIALIZERS. Cscope also
* groks this.
*
* ("SFINIT" == struct field init, but really, it can be used for array initializers too.)
*/
#ifdef HAVE_DESIGNATED_INITIALIZERS
#define SFINIT(f, v) f = v
#else
#define SFINIT(f, v) v
#endif
struct t {
char f1;
int f2;
double f3;
};
struct t t = {
SFINIT(.f1, 'a'),
SFINIT(.f2, 42),
SFINIT(.f3, 8.13)
};