正在声明指针的类型

Declaring type of pointers?

本文关键字:类型 指针 声明      更新时间:2023-10-16

我刚刚读到,在用C(或C++)声明指针时,我们需要给出指针的类型,即:

int *point ;

据我所知,指针存储变量的地址,地址占用的内存量与类型相同。那么,为什么我们需要声明它的类型呢?

类型安全。如果你不知道p应该指向什么,那么就没有什么可以防止像这样的类别错误了

*p = "Nonsense";
int i = *p;

静态类型检查是一个非常强大的工具,可以防止类似的各种错误。

C和C++还支持指针算术,只有在目标类型的大小已知的情况下才有效。

地址占用相同数量的内存,无论我是类型

今天流行的平台也是如此。但有些平台的情况并非如此。例如,指向多字节字的指针可能比指向单个字节的指针小,因为它不需要表示字中字节的偏移量。

因为:

  1. 不同类型的地址不需要具有相同的大小。本标准明确规定(C 2011标准(在线草案),6.2.5/28)
  2. 类型安全:这允许编译器检测何时提供指向函数的不兼容指针,或者在赋值中提供不兼容指针。这反过来又防止了将函数的参数顺序搞砸的丑陋情况
  3. 当指针被取消引用时,编译器需要知道类型
  4. 要进行指针运算,需要知道所指向对象的大小及其类型

最后两点不适用于void指针,这就是为什么它们不能被取消引用,并且不能对它们进行指针运算。该标准规定void指针必须足够大,可以容纳任何类型的指针(函数指针除外,函数指针完全不同),并且可以在不进行强制转换的情况下对void指针进行赋值(至少在C中,C++中总是需要强制转换)

一个原因是指针算术。除非知道p所指向的元素的大小,即p作为指针的类型的大小,否则无法执行p+1。如果你在void *p上尝试p+1,你很可能会得到一个糟糕的答案(这与在char *上尝试相同,但可能你不想这样;-pedantic会将其作为警告,-pedantic-errors会将其视为错误)。

另一个原因是类型安全。如果函数接收到作为参数的int *,则不能在那里传递指向char(字符串)的指针。您会收到警告(-Werror/-pedantic-errors出现错误)。考虑这个(伪)代码:

void test(int *x)
{
}
int main()
{
    char *x = "xyz";
    test(x);
    return 0;
}

编译(使用gcc (GCC) 4.8.2 20131017 (Red Hat 4.8.2-1))给出:

1.c: In function ‘main’:
1.c:8:2: warning: passing argument 1 of ‘test’ from incompatible pointer type [enabled by default]
  test(x);
  ^
1.c:1:6: note: expected ‘int *’ but argument is of type ‘char *’
 void test(int *x)
      ^

那么,为什么我们需要声明它的类型呢?

您想知道指针的类型,以便进行静态类型检查。

我们还需要知道指针运算的类型,例如,当我们对不同大小类型的数组(,相当于指针运算)进行索引时,指针将根据类型进行调整。如果我们看C99标准草案6.5.6加法运算符说(强调矿):

对于加法,两个操作数都应具有算术类型,或者一个操作数应为指向对象类型的指针[…]

因此,指针需要是对象类型,这意味着不完整或无效。

你还说:

地址占用的内存量与类型相同。那么,为什么我们需要声明它的类型呢?

这在C++中并不总是正确的。指向成员函数的指针的大小可能会根据类类型而变化,其中一篇很好的文章介绍了这一点。指向成员功能的指针是非常奇怪的动物。

此外,我们可以看到C99草案标准部分6.2.5类型段落27中都写道:

[…]指向其他类型的指针不需要具有相同的表示或对齐要求。

C++标准草案3.9.2化合物类型段落3说:

[…]指针类型的值表示是由实现定义的。布局兼容类型的cv合格和cv不合格版本(3.9.3)的指针应具有相同的值表示和对齐要求(3.11)。[…]

不要求指针具有相同的表示,除非在特定情况下。

您需要根据标准要求指定类型。此外,这样在尝试执行指针运算(如加法或减法)时就不会出现问题。

虽然处理器通常有不同的指令用于"从地址加载字节"、"从地址装载16位半字"answers"从地址装入32位字",但对于"存储"操作,C使用与加载任何其他大小值相同的语法从地址装载字节。给定声明:

int n = *p;

编译器可以生成从p中的地址加载字节、半字或字并将其存储到n中的代码;如果p是一个*float,它可能会生成一个更复杂的代码序列,将浮点值加载到c中,截断它,转换为int,并将转换后的值存储到n中。如果不知道p的类型,编译器就无法知道哪种操作是合适的。

同样,语句p++可以将p中的地址增加一个、两个、四个或一些其他数字。地址的增加量将取决于声明的p类型。如果编译器不知道p的类型,它就不知道如何调整地址。

可以在不指定指针所指向对象的类型的情况下声明指针。这种指针的类型是void*。然而,在使用void*做任何有用的事情之前,必须将其转换为真正的指针类型;void*的主要用途在于,如果指针被转换为void*,则它可以由对指针的实际类型一无所知的代码作为void*传递。如果指针最终被赋予确实知道其类型的代码,并且该代码将指针强制转换回该类型,则结果将与已转换为void*的指针相同。

必须处理指向它一无所知的事物的指针的代码通常可以有效地使用void*来实现这种目的,但知道指针指向的事物的代码通常应该声明正确类型的指针。

指针类型在取消引用和指针算术时发挥作用。例如

int x=10;     //Lets suppose the address of x=100
int *ptr=&x;   //ptr has value 100
printf("The value of x is %d", *ptr);
ptr++;  // ptr has value 104(if int is 4bytes)

在上面的例子中,指针类型是int,因此编译器将开始查找从存储器地址100开始的下4个字节(如果int是4个字节)中存储的值。因此,指针的类型告诉编译器在取消引用时应该查找多少字节。如果指针类型不在那里,编译器怎么会知道在解引用时要查找多少字节。当我们执行ptr++时,指针类型告诉ptr应该增加多少。此处ptr递增4。

char c='a';   //Lets suppose the address of c = 200
char* ptr=&c;   //ptr has value 200
ptr++;   //ptr has value 201(char assumed to be 1 byte) 

指针类型告诉ptr增加1个字节。

这样它就可以执行算术和其他操作。考虑以下两个例子:

int* p; /* let the address of the memory location p pointing to be 1000*/
p++;
printf("%u",p); /* prints 1004 since it is an integer pointer*/

char *p; /* let the address of the memory location p pointing to be 1000*/
p++;
printf("%u",p); /* prints 1001 since it is an char pointer*/

我希望这对你有帮助!

我们实际上不需要(见下文)来声明类型,但我们应该。指针存储有关对象位置的信息,而类型定义它在内存中占用的空间。

存储在指向内存中的对象的大小在各种情况下都是需要的——数组创建、分配、复制内存,最后使用new创建对象。

但是,如果您想隐藏(出于任何原因)类型:,您仍然可以定义void指针

void* dontKnowWhatTypeIsHere;

空指针被认为是通用指针。它可以指向任何对象,当我们想将它与类型一起使用时,我们只需要执行reinterpret_cast

前面有很多说法,但apan是完全正确的。现在你的问题为什么我们定义指针的类型指针的第一个定义一种指针,可以保存另一个变量的地址。上述定义是片面的。确切的定义是指针是一个可以保存变量地址的变量,如果我们取消引用(获取值)它,它将返回该地址上的当前值。如果指针未能在取消引用时返回值,则它不是指针。您可以尝试,即使在gcc编译器中,一个简单的变量也可以保存另一个变量的地址,但在取消引用时,它会给您带来错误。现在尺寸无论数据类型如何,指针的大小总是等于特定编译器上整数的大小。因此,在gcc编译器中指针的大小是4字节(整数大小),而在turbc中指针的尺寸是2字节(整数的大小)。现在的问题是为什么等于整数的大小。任何变量的地址都可以是int、char、float等。地址总是一个整数,整数存储在int中。这就是为什么指针的大小等于int的大小,因为它还存储始终是纯整数数据的地址。那么,任何其他数据类型指针的int和char之间的区别是什么呢。在检索时,你的编译器会根据你的数据类型获取字节数。其他方面,你会得到错误或不是错误,但对你来说是一些不可预测的结果,但对我来说不是。相同的规则适用于指针的递增和递减——它总是根据指针数据类型递增和递减。指针的大小不取决于数据类型,因此也不取决于你的链接列表出现的原因,因为如果你试图在同一个变量中声明结构,那么你会得到编译时错误,因为你的编译器在完整声明之前没有结构的大小,但允许相同结构的自引用指针,为什么?唯一的答案是指针的大小不取决于数据类型的大小。如果你有任何疑问,请问我。谢谢后的asif