15

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...

DinGODzilla
  • 1,611
  • 4
  • 21
  • 34
  • 1
    Note that the designated initializers feature was added in VS 2013: http://blogs.msdn.com/b/vcblog/archive/2013/06/28/c-11-14-stl-features-fixes-and-breaking-changes-in-vs-2013.aspx – ysap Feb 26 '15 at 16:53

3 Answers3

17

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    This is it :-) Assuming that non-listed fields must be initialized to 0/NULL explicitly (so arity matches). – DinGODzilla Mar 26 '11 at 06:46
  • 2
    Non listed **trailing** fields are set to 0. Unlike C99 you cannot skip other fields, as they must be given in order. – Bo Persson Mar 26 '11 at 06:56
  • 2
    @DinGODzilla: Arity is not required to match in C89/90, as long as you are using a nested pair of `{}` every time you want to skip to the next member of the array. That means that you only have to initialize the leading elements of the struct, while the trailing elements will be automatically set to zero. In this particular case intializing `type` field with `NULL` in C99 was unnecessary, just `.name = "something"` was enough (`type` would be set to null automatically), but in C89/90 you have to specify the `NULL` explicitly just to get to the next field `name`. – AnT stands with Russia Mar 26 '11 at 14:27
  • 1
    @DinGODzilla:..... in other words, it actually looks like your C99-style initializers were created by direct translation from C89/90-style initializers, which required an explicit `NULL` for the first field :) – AnT stands with Russia Nov 12 '13 at 01:09
  • 2
    _"...it is really a C89/90 compiler."_ No, MSVC is really a C++ compiler. They really don't give a rip about C at all anymore. – Rob K Aug 14 '14 at 15:30
3

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.

Stephan
  • 41,764
  • 65
  • 238
  • 329
cordic
  • 139
  • 3
  • Same as Nico's answer, this is not portable, as the initialization still ultimately depends on the order you pass the values in. In the worst case, this code compiles with different compilers but with different results... – Manuzor May 09 '16 at 13:36
1
/*
 * 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)
};
Nico
  • 324
  • 2
  • 2
  • 2
    I fail to see how this implements the designated initializers feature in C89? What if I change the order of values, or omit some, which is the whole point of this feature? – ysap Feb 26 '15 at 16:57
  • :-1: This is not a portable solution at all. The initialization behavior across compilers is basically undefined here. That looks more like a complicated way to annotate the arguments in the case of `HAVE_DESIGNATED_INITIALIZERS == 0`. – Manuzor May 09 '16 at 13:32