8

In GCC, I'm able to do this:

(CachedPath){ino}
inode->data = (struct Data)DATA_INIT;

where:

struct CachedPath
{
    Ino ino;
};

typedef int8_t Depth;
struct Data
{
    Offset size;
    Blkno root;
    Depth depth;
};
#define DATA_INIT {0, -1, 0}

MSVC gives the following error for these kind of casts:

error C2143: syntax error : missing ';' before '{'

How can I do this in MSVC? Further note that the code has been converted from C99, where I used designated initializers for this, and then cast it similarly. Any clarity on how these various features relate between C99, and MSVC/GCC implementations of C++ is appreciated.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • 2
    You might consider changing the title. Compound literals are not a cast operator. The set of types which are valid in a cast and the set which are valid for compound literals are completely disjoint, and the C standard makes a point of this. – R.. GitHub STOP HELPING ICE Oct 06 '10 at 06:46

4 Answers4

14

The construct (Type){initialisers} is not a cast operation, but it is the syntactic construct of a compound literal. This is a C99 construct, which GCC also supports in its C++ compiler as an extension. As far as I can determine, compound literals are not supported up to and including MSVC 2012, in either its C or C++ mode. The support in C mode was introduced later, in MSVC 2013. In C++ mode it is still not supported and I believe it is unlikely support will be added.

For MSVC 2012 and older, the alternatives for this construct are

  • Explicitly declare and initialise a temporary object of the desired struct type and use that instead of the compound literal in the assignment
  • Instead of doing a single assignment with the compound literal, use a separate assignment for each individual member.
Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
3

MSVC is not conformant to C99 and only loosely conformant to previous versions of the C standard. I know no way to do what you want syntactically with MSVC, but the same effect can be obtained by using static const structs instead of anonymous compound literal constants, and local struct variables that are initialized with the correct values instead of anonymous compound literals that are nonconstant.

The idea behind this approach is that a C99 compound literal is (at least nearly) equivalent to a local variable of the same type at the same scope, initialized with the contents of the braces. Using static const structs in the case where the data is constant is just an optimization (it will likely produce smaller/faster code than the C99 compound literal approach).

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 2
    MSVC is very precisely conformant to C89/90 standard. What is the strange claim of being "loosely conformant" based upon? – AnT stands with Russia Oct 06 '10 at 06:49
  • 2
    Most of the conformance problems I know about are the standard library and related to internationalization amendments ("C95" I think it's typically called). For instance, incorrect behavior of the `%s` and `%ls` format specifiers in `wprintf` and `printf`, respectively, and the use of multi-`wchar_t` characters (UTF-16) in ways that breaks the C multibyte/wide conversion API. I suspect the compiler/compilation environment itself has some bugs too though - like keyword/function/type names that conflict with those reserved for the application. – R.. GitHub STOP HELPING ICE Oct 06 '10 at 06:59
  • What do you mean by "use static const structs"? – Matt Joiner Oct 06 '10 at 07:12
  • Along with `#define DATA_INIT {0, -1, 0}`, use `static const struct Data data_init = DATA_INIT;`, and then use the latter for assignments and the former for initializations. – R.. GitHub STOP HELPING ICE Oct 06 '10 at 07:24
2

Visual Studio, since VS2013, supports Compound literals and Designated initializers. Which C99 features are available in the MS Visual Studio compiler?

Example:

// main.c
#include <stdio.h>

void func(int(*array)[3]);

int main()
{
    // Designated initializers

    int a[6] = { [4] = 29, [2] = 15 }; // [0, 0, 15, 0, 29, 0]

    struct point { int x, y; };
    struct point p = { .y = 13, .x = 27 }; // x = 27, y = 13

    union foo { int i; double d; };
    union foo f = { .d = 4 }; // d = 4.0

    struct point ptarray[5] = { [2].y = 34, [2].x = 42, [0].x = 58 };
    // (58 0), (0 0), (42 34), (0 0), (0 0)

    // Compound literals

    int *a1 = NULL;
    a1 = (int[6]) { [4] = 29, [2] = 15 }; // [0, 0, 15, 0, 29, 0]

    struct point p1;
    p1 = (struct point) { .y = 13, .x = 27 }; // x = 27, y = 13

    union foo f1;
    f1 = (union foo) { .d = 4 }; // d = 4.0

    struct point *ptarray1 = NULL;
    ptarray1 = (struct point[5]) { [2].y = 34, [2].x = 42, [0].x = 58 };
    // (58 0), (0 0), (42 34), (0 0), (0 0)

    int *p2 = NULL;
    p2 = (int[2]) { -1 };
    p2 = (int[]) { -73, 89, 92 };
    func(&(int[]) { -73, 89, 92 });

    return 0;
}

void func(int(*array)[3])
{
    for (int i = 0; i < 3; i++) {
        printf("%d ", (*array)[i]);
    }
}
infval
  • 318
  • 3
  • 4
0

MSVC is a mix of standards, and is not fully compliant with most of them, thus, you'll probably need to use a default initializer/constructor, like so (C++ way):

#define DATA_INIT 0,-1,0
inode->data = Data(DATA_INIT);

struct Data
{
    Offset size;
    Blkno root;
    Depth depth;

    Data(Offset size, Blkno root, Depth depth) : size(size), root(root), depth(depth)
    {
    }
};
Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • @R.. please read the tags and the OP's post, this is C++ code, like the OP requested – Necrolis Oct 06 '10 at 06:42
  • 1
    You've forgot to define a constructor accepting 3 parameters for `struct Data`. – atzz Oct 06 '10 at 06:59
  • @atzz: good catch, I'll add that, though I remember that MSVC could auto initialize without one, can't test that at the moment though – Necrolis Oct 06 '10 at 07:11
  • Yes, this would be great if C++ created a default constructor accepting all the members of the struct in order. – Matt Joiner Oct 06 '10 at 07:13