MSVC中的复合字面量

8
在GCC中,我能够做到这一点:
(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会给出以下错误提示:

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

如何在MSVC中实现这个功能?需要注意的是,该代码已从C99转换而来,在C99中我使用了指定初始化器,然后类似地进行了转换。如果能够解释C99和MSVC/GCC C++实现之间这些不同特性的关系,将不胜感激。


2
你可能需要考虑更改标题。复合字面量不是一个强制转换运算符。在强制转换和复合字面量中有效的类型集是完全不相交的,C标准也特别强调了这一点。 - R.. GitHub STOP HELPING ICE
4个回答

14
构造函数(Type){initialisers}不是一个强制转换操作,而是一种复合文字的语法结构。这是C99的构造,GCC也作为扩展支持在其C++编译器中。据我所知,复合文字在包括MSVC 2012在内的版本中都不受支持,无论是在C模式下还是在C++模式下。在C模式下的支持是稍后在MSVC 2013中引入的。在C++模式下仍然不受支持,并且我认为不太可能添加支持。
对于MSVC 2012及更早版本,此结构的替代方法是:
  • 明确声明和初始化所需结构类型的临时对象,并在赋值时使用该对象,而不是复合文字。
  • 不使用复合文字进行单个赋值,而是对每个单独成员使用单独的赋值。

3

MSVC不符合C99标准,只是松散地符合以前版本的C标准。我不知道如何在MSVC中以语法方式实现您想要的,但可以通过使用static const结构体代替匿名复合文字常量和本地初始化了正确值的struct变量代替非常量的匿名复合文字来获得相同的效果。

这种方法的思想是,C99复合文字(至少几乎)等同于在相同作用域内具有相同类型的局部变量,其内容已使用大括号初始化。在数据为常量的情况下使用static const结构体只是一种优化(它可能会产生比C99复合文字方法更小/更快的代码)。


2
MSVC非常精确地符合C89/90标准。那么所谓的“松散符合”是基于什么奇怪的主张呢? - AnT stands with Russia
2
我知道的大部分符合性问题都与标准库和国际化修正有关(我认为通常称为“C95”)。例如,在wprintfprintf中,%s%ls格式说明符的不正确行为,以及以破坏C多字节/宽转换API的方式使用多个wchar_t字符(UTF-16)。虽然我怀疑编译器/编译环境本身也存在一些错误 - 比如与应用程序保留的关键字/函数/类型名称冲突。 - R.. GitHub STOP HELPING ICE
“use static const structs” 是什么意思? - Matt Joiner
除了使用#define DATA_INIT {0,-1,0},还要使用static const struct Data data_init = DATA_INIT;,然后对赋值使用后者,而对初始化使用前者。 - R.. GitHub STOP HELPING ICE

2

自VS2013起,Visual Studio支持复合文字和指定初始化程序。

MS Visual Studio编译器可用哪些C99功能?

示例:

// 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]);
    }
}

0

MSVC 是由多种标准混合而成,因此不完全符合大部分标准,因此您可能需要使用默认的初始化器 / 构造函数,如下(C ++方式):

#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)
    {
    }
};

@R.. 请阅读标签和原帖,这是C++代码,正如OP所请求的。 - Necrolis
1
你忘记为“结构体Data”定义一个接受3个参数的构造函数。 - atzz
@atzz: 很好的发现,我会添加这个功能。尽管我记得 MSVC 可以在没有它的情况下自动初始化,但目前无法进行测试。 - Necrolis
如果C++可以创建一个默认构造函数,按顺序接受结构体的所有成员,那就太好了。 - Matt Joiner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接