Compound literals in MSVC
Asked Answered
T

4

9

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.

Touraco answered 6/10, 2010 at 6:24 Comment(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.Two
This "duplicate" predates the alternative by FIVE YEARS. Also the duplicate is GCC and clang specific, this is for MSVC.Touraco
C
15

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.
Corey answered 6/10, 2010 at 7:4 Comment(0)
T
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).

Two answered 6/10, 2010 at 6:31 Comment(4)
MSVC is very precisely conformant to C89/90 standard. What is the strange claim of being "loosely conformant" based upon?Dominoes
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.Two
What do you mean by "use static const structs"?Touraco
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.Two
I
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]);
    }
}
Increscent answered 16/11, 2018 at 4:26 Comment(0)
S
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)
    {
    }
};
Sadoff answered 6/10, 2010 at 6:35 Comment(4)
@R.. please read the tags and the OP's post, this is C++ code, like the OP requestedSadoff
You've forgot to define a constructor accepting 3 parameters for struct Data.Hiller
@atzz: good catch, I'll add that, though I remember that MSVC could auto initialize without one, can't test that at the moment thoughSadoff
Yes, this would be great if C++ created a default constructor accepting all the members of the struct in order.Touraco

© 2022 - 2024 — McMap. All rights reserved.