指针到底存储了啥? (C++)

Posted

技术标签:

【中文标题】指针到底存储了啥? (C++)【英文标题】:What exactly do pointers store? (C++)指针到底存储了什么? (C++) 【发布时间】:2010-11-02 17:34:02 【问题描述】:

我知道指针存储它们所指向的值的地址,但是如果将指针的值直接显示到屏幕上,则会得到一个十六进制数。如果数字正是指针存储的,那么当说

pA = pB; //both are pointers

您正在复制地址。那么在处理ints 和bools 等非常小的项目时,使用指针不会有更大的开销吗?

【问题讨论】:

+1 因为你 14 岁 :) 检查每个对象的大小。找出比指针小的东西。 sizeof() 是的,对于青少年来说确实是非常好的想法! 【参考方案1】:

指针本质上只是一个数字。它将地址存储在数据所在的 RAM 中。指针本身非常小(可能与 32 位架构上的 int 和 64 位架构上的 long 大小相同)。

您是对的,尽管 int * 在使用 ints 时不会节省任何空间。但这不是重点(不是双关语)。指针在那里,因此您可以对事物进行 引用,而不仅仅是使用 事物 本身。

【讨论】:

在 C++ 中有一个明确的参考概念。存在指针的原因是能够管理动态分配的内存,而不是引用。 @dribeas:我不是指 C++ 引用,我指的是理论概念,即拥有一些东西,它只是告诉你在哪里可以找到东西,所以你可以共享数据。 指针也可以节省空间和时间。这就是我们使用写时复制的原因。【参考方案2】:

内存地址。

这是内存中其他东西所在的位置

指针通常是处理器的字长,因此它们通常可以在单个指令周期内移动。简而言之,它们很快。

【讨论】:

这对于单个副本是正确的,但是您可以在单个时钟周期内复制多个 bool 或 int(数组中的 8x bool 与复制单个指针相同)。此外,将指针存储在类中会不必要地增大它们的大小并导致分配速度变慢。【参考方案3】:

正如其他人所说,指针存储的内存地址“只是一个数字”,但这是一种抽象。根据处理器架构,它可能不止一个数字,例如必须添加到的基数和偏移量取消引用指针。在这种情况下,开销比地址为单个数字时略高。

是的,通过指针与直接访问 int 或 bool 存在开销,处理器可以将变量放入寄存器中。指针通常用于间接值超过任何开销的地方,即遍历数组。

我指的是时间开销。不确定 OP 是否更关心空间或时间开销。

【讨论】:

【参考方案4】:

数字是指它在内存中的地址。指针的大小通常是计算机体系结构的本机大小,因此与任何其他原始类型相比没有额外的开销。

【讨论】:

在现代机器上,int 通常是 32 位的,而指向变量的点通常是 64 位的。像 char 这样的基本数据类型在 C/C++ 中一直小于指针。因此,OP 的观察是正确的:如果数据类型小于您的指针,请不要尝试使用指针/引用来节省时间或内存。这是一个常见的新手错误。【参考方案5】:

在某些架构上,指向字符的指针会产生额外的开销,因为该架构仅支持寻址字(32 位或 64 位值)。因此,指向字符的指针被存储为字地址和该字中字符的偏移量。取消引用指针涉及获取单词,然后移动和屏蔽它的值以提取字符。

【讨论】:

【参考方案6】:

让我从基础开始。首先,您必须知道什么是变量以及如何使用它们。

变量基本上是内存位置(通常包含一些值),我们使用一些标识符(即变量名)来引用该内存位置并使用该位置存在的值。

为了更好地理解它,假设我们希望内存单元的信息出现在相对于当前变量的某个位置。我们可以使用标识符从附近的单元格中提取信息吗? 不会。因为标识符(变量名)只会给出该特定单元格中包含的值。

但是,如果我们能以某种方式获得该变量所在的内存地址,那么我们可以轻松移动到附近的位置并使用它们的信息(在运行时)。

这就是指针发挥作用的地方。它们用于存储该变量的位置,以便我们可以在需要时使用其他地址信息。

语法:要存储变量的地址,我们可以简单地使用 & (address-of) 运算符。

foo = &bar 

这里 foo 存储变量 bar 的地址。

现在,如果我们想知道该地址的值怎么办?

为此,我们可以简单地使用 *(取消引用)运算符

value = *foo

现在我们必须存储变量的地址,我们需要内存的方式与存储变量的方式相同。这意味着指针也像其他变量一样存储在内存中,所以就像变量一样,我们也可以将指针的地址存储到另一个指针中。

【讨论】:

【参考方案7】:

内存中的地址。指向某个地方! :-)

【讨论】:

你没有回答OP的问题,OP在问题中说他已经知道了。【参考方案8】:

是的,就速度和内存而言,你是对的。

指针几乎总是占用比标准int 更多的字节,尤其是boolchar 数据类型。在现代机器上,指针通常是 8 个字节,而 char几乎总是只有 1 个字节。

在本例中,从Foo 访问charbool 比从Bar 访问需要更多的机器指令:

struct Foo

    char * c; // single character
    bool * b; // single bool
;

struct Bar

    char c;
    bool b;
;

...如果我们决定创建一些数组,那么Foo 的数组大小将大 8 倍 - 并且代码更加分散,因此这意味着您最终将拥有很多更多缓存未命中。

#include <vector>

int main()

    int size = 1000000;
    std::vector<Foo> foo(size);
    std::vector<Bar> bar(size);

    return 0;

正如 dmckee 所指出的,单字节 bool 的单个副本和指针的单个副本一样快:

bool num1, num2,* p1, * p2;
num1 = num2; // this takes one clock cycle
p1 = p2; // this takes another

正如 dmckee 所说,当您使用 64 位架构时确实如此。

但是,ints、bools 和 chars 数组的复制会快得多,因为我们可以将它们的倍数压缩到每个寄存器中:

#include <iostream>

int main ()

    const int n_elements = 100000 * sizeof(int64_t);

    bool A[n_elements];
    bool B[n_elements];

    int64_t * A_fast = (int64_t *) A;
    int64_t * B_fast = (int64_t *) B;

    const int n_quick_elements = n_elements / sizeof(int64_t);

    for (int i = 0; i < 10000; ++i)
        for (int j = 0; j < n_quick_elements; ++j)
            A_fast[j] = B_fast[j];

    return 0;

使用type_traits (is_trivially_copyable) 和std::memcopy,STL 容器和其他优秀的库为我们做这种事情。假装指针总是一样快,会阻碍这些库的优化。

结论:这些示例看起来很明显,但仅当您需要获取/授予对原始对象的访问权限时,才对基本数据类型使用指针/引用。

【讨论】:

以上是关于指针到底存储了啥? (C++)的主要内容,如果未能解决你的问题,请参考以下文章

C++入门基础教程:C语言的指针与结构体到底怎么用?

C++入门基础教程:C语言的指针与结构体到底怎么用?

printf 在这里做了啥?

vulkan API 复制了啥?

C++引用在本质上是什么,它和指针到底有什么区别?

在 C++ 中使用指针和指向指针的指针读取和存储序列化对象的快速方法