考虑下面的片段,以说明问题:
#include <cstdio>
struct A {
union {
struct { int a0, a1; } aa;
int bb[2];
};
#if 1 //bug
constexpr A(int a0, int a1) : aa{a0, a1} {}
#else //OK
constexpr A(int a0, int a1) : bb{a0, a1} {}
#endif
};
int main() {
A t0{2, 3}; std::printf("%d %d\n", t0.aa.a0, t0.aa.a1); //2 3 (OK)
static A t1{2, 3}; std::printf("%d %d\n", t1.aa.a0, t1.aa.a1); //2 3 (OK)
constexpr A t2{2, 3}; std::printf("%d %d\n", t2.aa.a0, t2.aa.a1); //2 3 (OK)
static constexpr A t3{2, 3}; std::printf("%d %d\n", t3.aa.a0, t3.aa.a1); //0 0 (??)
}
msvc 2015更新3和2017 rc1 通过零初始化t3而不是使用给定值正确初始化来静默生成错误代码。 gcc和clang很好。
我研究报告了一个错误,但这太麻烦了(我不使用IDE)。如果您在意,请确认这是一个错误,并告知微软可能关注谁。
答案 0 :(得分:2)
我可以在VS 2015上使用x86-32和x86-64编译器重现这一点。
我还可以确认当前版本的GCC,Clang和ICC正确编译它。我也无法在禁止您正在做的事情的语言标准中找到任何内容。无论是在编译时(如您所期望的那样)还是在运行时初始化对象,都允许实现一些余地,但MSVC根本不对其进行初始化。
正如可能预期的那样,当对象的声明被移动到命名空间范围时,会出现同样的问题,例如 :
$scope.filepath = function () {
console.log($scope.mdphoto);
}
...以及如果对象被声明为其他空结构的静态成员。
虽然可见效果是零初始化,但实际上并不是编译器正在做的事情。相反,它在相应的数据段中根本无法发出值,因此当代码在调用#include <cstdio>
struct A {
union {
struct { int a0, a1; } aa;
int bb[2];
};
constexpr A(int a0, int a1) : aa{a0, a1} { }
};
namespace {
constexpr A t3 { 2, 3 };
};
int main() {
std::printf("%d %d\n", t3.aa.a0, t3.aa.a1);
}
时尝试从该地址加载一个值以推送到堆栈时,它最终会推送零
似乎这里printf
是重现错误的关键。如果union
仅包含结构A
,则没有问题。简单地删除aa
以留下一个成员联盟也可以解决问题。
请注意,您在submit a bug report to Microsoft for the VS 2017 compiler处拥有所需的一切(不需要使用IDE)。问题中包含的代码是一个独立的示例,可以很好地演示问题。如果你真的不想自己做,请告诉我,我会提交错误。