Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么这个指针是空的_C++_Visual Studio_Language Lawyer - Fatal编程技术网

C++ 为什么这个指针是空的

C++ 为什么这个指针是空的,c++,visual-studio,language-lawyer,C++,Visual Studio,Language Lawyer,在VisualStudio中,似乎指向成员变量的指针在幕后是32位有符号整数(即使在64位模式下也是如此),在该上下文中,空指针是-1。如果我有一门课,比如: #包括 #包括 结构Foo { 字符arr1[INT_MAX]; 字符arr2[INT_MAX]; char ch1; 煤焦ch2; }; int main() { 自动p=&Foo::ch2; std::cout当我测试代码时,VS显示Foo:类太大了。 当我添加char arr3[INT_MAX]时,Visual Studio将报告

在VisualStudio中,似乎指向成员变量的指针在幕后是32位有符号整数(即使在64位模式下也是如此),在该上下文中,空指针是-1。如果我有一门课,比如:

#包括
#包括
结构Foo
{
字符arr1[INT_MAX];
字符arr2[INT_MAX];
char ch1;
煤焦ch2;
};
int main()
{
自动p=&Foo::ch2;

std::cout当我测试代码时,VS显示
Foo:类太大了。

当我添加
char arr3[INT_MAX]
时,Visual Studio将报告
错误C2089'Foo':'struct'太大
。Microsoft文档将其解释为
指定的结构或联合超过了4GB限制。

根据标准[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]


[2] 表达式
&Foo::ch2
的类型为
char-Foo::*
,它是指向类
Foo
成员的指针。根据规则,只有当指向转换为
bool
的成员的指针为空指针时,才应将其计算为false,也就是说,为其分配了
nullptr

此处的错误似乎是实现的缺陷。即,在具有-march=x86-64的gcc编译器上,任何分配给成员的指针计算结果都为非null(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';
}
很可能是因为类大小超过了平台限制,导致成员的偏移量为0(nullptr的内部值).Compiler没有检测到它,因为它成为带符号值的整数溢出的牺牲品,程序员的错误是使用带符号的文本作为数组大小在编译器中导致UB:LLONG_MAX+LLONG_MAX=-2将是两个数组组合的“大小”

基本上,前两个成员的大小计算为,ch1的偏移量为
-2
,表示为无符号
18446744073709551614
。 而
-2
因此指针不是空的。另一个编译器可能会将值钳制为0,产生一个空PTR,或者像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';

第一个成员的偏移量显然是0,如果指针表示偏移量,那么它需要另一个值来表示
nullptr
。合理的假设是,这个特定的编译器只将
-1
视为空值,这对于其他实现来说可能是,也可能不是。

这显然是一个选项之间的冲突对成员表示的指针进行亚胺化(当不存在虚拟基时,仅使用4字节的存储空间)和鸽子洞原理

对于包含
char
类型的
N
子对象的
X
类型,有
N+1
可能的有效指针指向
char X:*
…类型的成员,每个子对象一个指针,一个指针指向成员的空指针


当指向成员表示的指针中至少有N+1个不同的值时,这就起作用了。对于4字节表示,这意味着在我的测试中,
N+1
,只有当我添加第三个包含INT\u MAX元素的数组时才会发生错误。其他注释也验证了我观察到的两个数组的行为。也许你没有进行干净的构建?我不确定。我已经清理并重建了我的编译器,这可能与每个人的编译器设置有关。我的意思是,这可能是因为结构中的元素超出了
struct
编译器的限制。有趣的是,当您在中注释掉
char ch1;
或将
INT\u MAX
更改为
时T_MAX-1
,程序的结果是
不为NULL
。这是因为该类被仔细编写,以干净地环绕指向-1的指针。当您更改内容时,不会发生这种情况。请。仅将图像用于无法表示为文本或扩充文本的内容。在图像中包含图例/键和说明。@edoardoroso为什么要这样做你认为它有垃圾值吗?我认为你应该读@edoardoroso不,你错了。struct是一个类。@edoardoroso不,它不是垃圾。成员指针根本不是指针。它不需要对象存在。@BillLynch偏移量分别为0、2147483647、4294967294、4294967295。这似乎是正确的。IntelliSense解析器corre编译器没有发现问题。这有点棘手,因为这个问题只能在后端检测到。这是x64代码生成器的限制,对象不能大于2GB。除此之外,需要使用非常不同的方法生成地址,LEA由于置换溢出而无法再工作。不可用e、 使用“帮助”>“发送反馈”>“报告与对象大小有关的问题”,我们这里没有类型为
Foo
的对象。@AyxanHaqverdili:严格来说,MSVC对类型的大小有限制,这确实可能与对象大小的限制略有不同(特别是在数组方面).附录B允许这两个限制,但仅建议对象的值。因此,答案是我导致了未定义的行为,或者编译器应该拒绝此代码?这是未定义的行为当您超过所述limi时会发生什么
std::cout << reinterpret_cast<signed long long&&> (offsetof(foo, ch1)) << '\n';
std::cout << reinterpret_cast<signed long long&&> (offsetof(foo, ch2)) << '\n';
-2
-1