指针到底存储了啥? (C++)
Posted
技术标签:
【中文标题】指针到底存储了啥? (C++)【英文标题】:What exactly do pointers store? (C++)指针到底存储了什么? (C++) 【发布时间】:2010-11-02 17:34:02 【问题描述】:我知道指针存储它们所指向的值的地址,但是如果将指针的值直接显示到屏幕上,则会得到一个十六进制数。如果数字正是指针存储的,那么当说
pA = pB; //both are pointers
您正在复制地址。那么在处理int
s 和bool
s 等非常小的项目时,使用指针不会有更大的开销吗?
【问题讨论】:
+1 因为你 14 岁 :) 检查每个对象的大小。找出比指针小的东西。 sizeof( 是的,对于青少年来说确实是非常好的想法! 【参考方案1】:指针本质上只是一个数字。它将地址存储在数据所在的 RAM 中。指针本身非常小(可能与 32 位架构上的 int
和 64 位架构上的 long
大小相同)。
您是对的,尽管 int *
在使用 int
s 时不会节省任何空间。但这不是重点(不是双关语)。指针在那里,因此您可以对事物进行 引用,而不仅仅是使用 事物 本身。
【讨论】:
在 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
更多的字节,尤其是bool
和char
数据类型。在现代机器上,指针通常是 8 个字节,而 char
几乎总是只有 1 个字节。
在本例中,从Foo
访问char
和bool
比从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 位架构时确实如此。
但是,int
s、bool
s 和 char
s 数组的复制会快得多,因为我们可以将它们的倍数压缩到每个寄存器中:
#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++)的主要内容,如果未能解决你的问题,请参考以下文章