为什么我们不能推广指针声明?

时间:2017-02-27 17:42:19

标签: c++ c pointers

指针的大小是相同的,与它指向的数据类型无关。那为什么我们需要声明它指向的数据类型?

例如,

int *p;  //p will point to an integer data type.
char *p;  //p will point to a character

然后,为什么我们不能概括像这样的指针声明

pointer p;  //where p is an object of pointer class.

6 个答案:

答案 0 :(得分:13)

TL; DR 因为,不同的数据类型在内存中占用不同的大小,并且具有不同的对齐要求。

详细说明,指针变量包含指向某种类型数据的地址。如果没有关联的类型,就无法取消引用指针并获取

换句话说,要访问指针指向的数据,必须知道相关的数据类型。

指针本身的大小与它指向的实际数据几乎没有联系。

存在一个指针,void *被认为是泛型指针,但是,您不能取消引用它,因为取消引用的结果会尝试生成不完整的类型。您需要将其强制转换为完整类型,以便能够取消引用或对void指针应用指针算法。

考虑void * 泛型指针的原因如下,引用C11标准,第3.6.2.3章

  

指向void的指针可以转换为指向任何对象类型的指针。指向的指针   任何对象类型都可以转换为指向void并再次返回的指针;结果应该   比较等于原始指针。

因此,void *可以用作通用容器,它可以保存任何指针类型,但是对指针进行一些操作(包括数据类型的知识) ,你需要先把它变成一个完整的类型。

答案 1 :(得分:6)

指针算法。

说明:

int arr[] = {4, 6, 9, 10};
int* x = arr;

*(x+0) = 4
*(x+1) = 6

编译器知道x + 1实际上是x + sizeof(int)而不是1。

要读取第二个元素,编译器每次都必须跳过sizeof(int)。在不知道实际类型的情况下,您无法取消引用它并正确提取数据。

Plus类型的大小不同,编译器需要知道从指向的内存中读取多少字节。 char将是1个字节,int将超过1个字节。

答案 2 :(得分:6)

可以使用void*来推广指针。 void*是指向某个地址的指针,没有任何关联的类型信息。但是,如果不将这些指针首先转换为显式指针类型,则几乎无法使用这些指针。

考虑以下示例。它不会编译,因为不可能推导出ptr指向的“值”。你甚至不知道该值构成了多少字节。

void print(const void * ptr) {
    std::cout << *ptr; // What's the "value" of ptr?
}

答案 3 :(得分:2)

void *指针可以被视为“通用”指针。

但是,它不能被解除引用,因为通用它并不指向任何一种类型的对象。要实际使用一个void *指针并访问它指向的内容,您需要将其转换为您正在访问的对象类型。

由于它没有指向任何一种类型的对象,因此没有正确的方法在void *指针上执行指针算法。

答案 4 :(得分:1)

  

无论指向的数据类型如何,指针的大小都是相同的。

这不一定正确 - 指向不同类型的指针可能具有不同的大小和表示:

指向void的指针应具有与a相同的表示和对齐要求 指向字符类型的指针。 48)同样,指向合格或非限定版本的指针 兼容类型应具有相同的表示和对齐要求。所有 指向结构类型的指针应具有相同的表示和对齐要求 彼此相同。所有指向联合类型的指针都应具有相同的表示形式 对齐要求彼此。 指向其他类型的指针不必相同 表示或对齐要求

C 2011 Online Draft,§6.2.5¶28

指针类型的值表示 是实现定义的。布局兼容类型的指针应具有相同的值表示和 对齐要求(3.11)。

C++ 2014 Working Draft,§3.9.2,¶3

在大多数现代桌面和服务器上,它们是相同的,但不要指望它普遍适用。

  

那么为什么我们需要声明它指向的数据类型?

指针算法取决于指向的类型 - 如果p指向类型为T的对象,则p + 1指向类型为T的下一个对象。由于不同类型具有不同的大小,因此您需要知道指向类型以正确计算偏移量。

答案 5 :(得分:0)

  

然后,为什么我们不能概括像这样的指针声明

 pointer p;  //where p is an object of pointer class.

您实际上可以使用void*。但结果是在那一点上所有类型(和大小信息)都丢失了。

你必须以某种方式(硬编码类型演员或其他)跟踪这些,以使其有用。