在Visual Studio中,指向成员变量的指针似乎是幕后的32位有符号整数(即使在64位模式下也是如此),而空指针在该上下文中是-1。所以如果我有一个这样的类:
#include <iostream>
#include <cstdint>
struct Foo
{
char arr1[INT_MAX];
char arr2[INT_MAX];
char ch1;
char ch2;
};
int main()
{
auto p = &Foo::ch2;
std::cout << (p?"Not null":"null") << '\n';
}它编译并打印"null“。那么,是我导致了某种未定义的行为,还是编译器应该拒绝这些代码,这是编译器中的一个bug?
编辑:
看起来我可以保持"2个INT_MAX数组加2个字符“的模式,只有在这种情况下,编译器才允许我添加任意多的成员,并且第二个字符总是被认为是空的。See demo。如果我稍微改变了模式(比如1或3个字符,而不是2个),它会报告类太大了。
发布于 2020-10-08 09:52:07
根据标准1的附件B,对象的大小限制是由实现定义的。您的结构的大小很荒谬。
如果结构是:
struct Foo
{
char arr1[INT_MAX];
//char arr2[INT_MAX];
char ch1;
char ch2;
};..。在相对较新的64位MSVC版本中,结构的大小似乎约为2147483649字节。如果你再加上arr2,sizeof会突然告诉你Foo的大小是1。
C++标准(附件B)规定,编译器必须记录限制,MSVC做了2。它规定它遵循推荐的限制。附件B,第2.17节提供了262144(?)对象的大小。虽然很明显MSVC可以处理更多,但它记录了它遵循最低建议,所以我认为当您的对象大小超过这个大小时,您应该小心。
1
发布于 2020-10-08 16:44:54
表达式&Foo::ch2的类型为char Foo::*,它是指向类Foo的成员的指针。根据规则,仅当指向已转换为bool的成员的指针为空指针时,才应将其计算为false,即为其分配了nullptr。
这里的错误似乎是实现的缺陷。也就是说,在带有-march=x86-64的gcc编译器上,任何指向成员的赋值指针都会计算为非空(1),除非它使用以下代码为其赋值为nullptr:
struct foo
{
char arr1[LLONG_MAX];
char arr2[LLONG_MAX];
char ch1;
char ch2;
};
int main()
{
char foo::* p1 = &foo::ch1;
char foo::* p2 = &foo::ch2;
std::cout << (p1?"Not null ":"null ") << '\n';
std::cout << (p2?"Not null ":"null ") << '\n';
std::cout << LLONG_MAX + LLONG_MAX << '\n';
std::cout << ULLONG_MAX << '\n';
std::cout << offsetof(foo, ch1) << '\n';
}输出:
Not null
null
-2
18446744073709551615
18446744073709551614这可能与类大小超出平台限制有关,导致成员的偏移量被包裹在0左右(nullptr的内部值)。编译器没有检测到它,因为它成为...的受害者。带符号值的整数溢出,这是程序员的错误,在编译器中使用有符号文字作为数组大小导致UB : LLONG_MAX + LLONG_MAX = -2将是两个数组组合的“大小”。
实际上,前两个成员的大小计算为无符号负数,ch1的偏移量为-2,表示为无符号18446744073709551614。因此,-2指针不为null。另一个编译器可能会将值钳制为0,从而产生nullptr,或者像clang一样实际检测到存在的问题。
如果ch1的偏移量是-2,那么ch2的偏移量是-1?让我们添加这个:
std::cout << reinterpret_cast<signed long long&&> (offsetof(foo, ch1)) << '\n';
std::cout << reinterpret_cast<signed long long&&> (offsetof(foo, ch2)) << '\n';其他输出:
-2
-1第一个成员的偏移量显然是0,如果指针表示偏移量,那么它需要另一个值来表示nullptr。假设这个特定的编译器只将-1视为空值是合乎逻辑的,对于其他实现,这可能是也可能不是。
发布于 2020-10-01 10:29:28
当我测试代码时,VS显示Foo: the class is too large。

当我添加char arr3[INT_MAX]时,Visual Studio将报告Error C2089 'Foo': 'struct' too large。Microsoft Docs将其解释为The specified structure or union exceeds the 4GB limit.

https://stackoverflow.com/questions/64143169
复制相似问题