How to rewrite C-struct designated initializers to

2019-02-12 00:57发布

问题:

guys, I've this problem:

Normally in C99 GCC (cygwin / MinGW / linux), there is dot-notation syntax for initializers in C struct.
Like this:

//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"},
};

Having my_memeber_t defined in header file as:

struct my_member_t {
    struct complex_type * type;
    char * name;
    int default_number;
    void * opaque;
};

I'm compiling linux code in MSVC 9.0 (Visual Studio 2008), on cygwin/MinGW this works ok.
BUT cl is unable to compile this (because of miserable C99 implementation): error C2059: syntax error : '.'

PROBLEM:
How to rewrite (many) global structs in a way that MSVC
(resp C89)can compile it?


Best regards and thanks for suggestions...

回答1:

Miserable C99 implementation? I don't think that C compiler in VC2008 even tries to implement C99. It might borrow some features, but it is really a C89/90 compiler.

Just drop the field name tags

static struct my_member_t my_global_three[] = {
    { NULL, "one"},
    { NULL, "two"},
    { NULL, "three"},
};

In this case it is easy, since the order of the initializers in the original code is the same as the order of fields in the struct. If the order was different, you'd have to rearrange them in the tagless C89/90 version.

And if it's really your my_member_t, then you should either declare the string pointer as const char * or stop initializing these members with string literals.



回答2:

Thanks for your information, Nico.

However, I have found out that for structs with arrays inside do not work. I propose this modification that works for both in C99 and MSVC (verified in MSVC++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}),
};

This way you can use one single file for MSVC and other compilers.



回答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)
};