简体   繁体   English

自引用指针算法

[英]Self-referential pointer arithmetic

So given the following code: 所以给出以下代码:

#include <iostream>
#include <vector>

int main(int argc, char* argv[]) {
    int i = 42;
    int* p = &i;

    std::cout << "*p: " << *p << std::endl;
    std::cout << "&p: " << &p << std::endl;
    std::cout << "p: " << p << std::endl;
    std::cout << "p + 1: " << (p + 1) << std::endl;
    std::cout << "p + 1: " << ((p + 1) == (int*)(&p)) << std::endl;
    std::cout << "*(p + 1): " << *(p + 1) << std::endl;
    return 0; 
}

It might produce the following output: 它可能会产生以下输出:

*p: 42
&p: 0x7fff38d8a888
p: 0x7fff38d8a884
p + 1: 0x7fff38d8a888
p + 1: 1
*(p + 1): 953723012

Is (p + 1) a pointer to the memory location p is stored in? (p + 1)指向存储位置p的指针存储在? Is it possible to get the value pointed by p by this way? 是否可以通过这种方式获得p指向的值?

In your example (p + 1) does not point to any storage you have allocated, so dereferencing it produces undefined behavior and should be avoided. 在您的示例中(p + 1)未指向您已分配的任何存储,因此取消引用它会产生未定义的行为,应该避免。

EDIT: Also, your second output for (p + 1) itself is unreliable, since pointer arithmetic should be used only if the pointer is a pointer to an array. 编辑:此外,您的第二个输出(p + 1)本身是不可靠的,因为只有当指针是指向数组的指针时才应使用指针运算。 Consequently, the expression evaluates to false on my machine. 因此,表达式在我的机器上评估为false

p is the pointer to an int object. p是指向int对象的指针。 &p is the address of p. &p是p的地址。

The stack from your example looks like: 您的示例中的堆栈如下所示:

Address        Type       Name        Value
0x7fff38d8a884 int        i           42
0x7fff38d8a888 int*       p           0x7fff38d8a884

The way that the stack has been setup, the address of p is right after the address of i. 堆栈的设置方式,p的地址就在i的地址之后。 In this particular case, when you added 1 to p, it moved 4 bytes down and found the value there, which happens to be the address to i. 在这种特殊情况下,当你向p添加1时,它向下移动了4个字节,并在那里找到了值,这恰好是i的地址。

What is happening in the line 行中发生了什么

std::cout << "p + 1: " << ((p + 1) == (int*)(&p)) << std::endl;

is p+1 --> compiler gets address for the "second element" of array p (int*)(&p) --> &p is an int** , but is being cast to an int* , int this particular instance, that happens to be the same as the value stored in p + 4 bytes p+1 - >编译器获取数组p (int*)(&p)的“第二个元素”的地址 - > &p是一个int** ,但是被强制转换为int* ,int这个特定的实例,这恰好与存储在p + 4字节中的值相同

What is happening in the line 行中发生了什么

std::cout << "*(p + 1): " << *(p + 1) << std::endl;

is *(p+1) --> compiler accesses the "second element" of array p, because you are likely using an x86_64 system, which is little endian, the hex value stored there is 0x38D8A884, the lower half of the pointer stored in p (which converts to 953723012 in decimal),. *(p+1) - >编译器访问数组p的“第二个元素”,因为你可能使用的是x86_64系统,这是小端,存储的十六进制值是0x38D8A884,存储指针的下半部分在p(十进制转换为953723012),.

If you remember that pointers and arrays can be used interchangeably, you might figure out that eg 如果你还记得指针和数组可以互换使用,你可能会发现,例如

p[1]

is the same as 是相同的

*(p + 1)

That means that the expression (p + 1) is a pointer to the int value after p . 这意味着表达式(p + 1)是指向p后的int值的指针。 As p doesn't point to an array, it means that (p + n) for a positive n is a pointer to something you haven't allocated (it's out of bounds), and reading that value leads to undefined behavior. 由于p不指向数组,这意味着正n (p + n)是指向未分配的东西的指针(它超出界限),并且读取该值会导致未定义的行为。 Assigning to it is also undefined behavior, and can even overwrite other variables data. 分配给它也是未定义的行为,甚至可以覆盖其他变量数据。

To get the address of where p is stored, you use the address-of operator: &p . 要获取存储p的地址,可以使用address-of运算符: &p That returns a pointer to the pointer (ie of type int ** ). 返回指向指针的指针(即int **类型)。

While the standard gives you no guarantee that ((p + 1) == (int*)(&p)) you seem to be lucky here. 虽然标准不能保证((p + 1) == (int*)(&p))你似乎很幸运。

Yet since you are on a 64-bitmachine when dereferencing (p+1) you get only the lower 32 bits of p. 然而,由于你在解除引用(p+1)时使用的是64位机器,因此只得到p的低32位。

0x38D8A884 == 953723012

The right hand side of the equation is the output that you received. 等式的右边是您收到的输出。 The left hand side is the lower 32 bits of p as witnessed by the output of your program. 左侧是p的低32位,如程序输出所见。

No. 没有。

Pointer arithmetic, although unchecked, is very limited by the Standard. 指针算术虽然未经检查,但受标准的限制。 In general, it should only be used within an array, and you may use it to point to either an array element or one past the end of the array. 通常,它只应在数组中使用,并且您可以使用它指向数组元素或超出数组末尾的数组元素。 Furthermore, although pointing one past the end of an array is allowed, the so-obtained pointer is a sentinel value which should not be dereferenced. 此外,虽然允许指向超过数组末尾的一个,但是如此获得的指针是不应被解除引用的标记值


So, what is it that you observe ? 那么,你观察到了什么? Simply put, &p , p + 1 , etc... are temporary expressions whose result have to be materialized somewhere. 简单地说, &pp + 1等......是临时表达式,其结果必须在某处实现。 With optimizations on, said results would probably be materialized in CPU registers, but without they are materialized on the stack within the function frame (in general). 通过优化,所述结果可能会在CPU寄存器中实现,但如果没有它们在功能框架内的堆栈中实现(通常)。

Of course, this location is not prescribed by the Standard, so trying to obtain it produces undefined behavior ; 当然,标准没有规定这个位置,所以试图获得它会产生不确定的行为 ; and even though it appears to work on your compiler with this set of compiling options means nothing for any other compiler or even this very same compiler with any other set of options. 即使它似乎在您的编译器上工作, 组编译选项对任何其他编译器都没有任何意义,甚至对于任何其他选项集也没有任何意义。

That is the true meaning of undefined behavior : it does not mean the program crashes, it just means anything may happen and this encompasses the seems to work situations. 这是未定义行为的真正含义:它并不意味着程序崩溃,它只意味着任何可能发生的事情,这包括似乎工作情况。

It is a random case that p + 1 is equal to &p. 随机情况是p + 1等于&p。 It takes place only in such code as yours where pointer p follows the object it points to. 它只发生在你的代码中,其中指针p跟随它指向的对象。 That is the address of p itself is sizeof( int ) greater than the address of the object it points to. 这就是p本身的地址是sizeof(int)大于它指向的对象的地址。 If you for example will insert one more definition between i and p then the equation p + 1 == &p will not be valid. 例如,如果您在i和p之间插入一个更多的定义,则等式p + 1 ==&p将无效。 For example 例如

int i = 42;
int j = 62;
int* p = &i;

p just so happened to get allocated on the stack at the address right after (well 4 bytes after) the address of the integer i. p恰好在整数i的地址之后(在4个字节之后)的地址处被分配在堆栈上。 some_ptr+1 (which is really some_ptr+1*sizeof(int)) is not a consistent way to get the address of some_ptr, it is just a coincidence in this case. some_ptr + 1(实际上是some_ptr + 1 * sizeof(int))不是获取some_ptr地址的一致方法,在这种情况下只是巧合。

so to answer your question some_ptr+1 != &some_ptr 所以回答你的问题some_ptr + 1!=&some_ptr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将类型参数传递给自引用指针 - Passing type parameter to self-referential pointer 如何破坏包含自指指针的对象? - How to destruct object containing self-referential pointer? 如何为具有自引用指针的类实现复制构造函数/赋值运算符? - How to implement a copy constructor / assignment operator for a class that has a self-referential pointer? memory如何在C/C++中使用自引用结构指针的结构声明中工作? - How does memory work in declaration of structure which uses self-referential structure pointer in C/C++? 没有对象或结构的自引用typedef - Self-referential typedef without object or struct 如何在C ++中定义自引用映射? - How to define a self-referential map in C++ ? C ++中Tupper的自引用公式无法按预期工作? - Tupper’s Self-Referential Formula in C++ not working as expected? 如何在C ++中声明自引用容器? - How to declare a self-referential container in C++? 自引用使用unordered_map会导致gcc 5.3而不是clang出现问题 - Self-referential use of unordered_map causes problems for gcc 5.3 but not clang 可以在 C++ 中实例化和/或专门化递归/自引用模板(使用指针)吗? - Can a recursive/self-referential template (using pointers) be instantiated and/or specialized in C++?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM