在当前的标准草案(和C 17)中,这是关于静态强制转换一个< code>void *:
“指向cv1 void的指针”类型的prvalue可以转换为“指向cv2 T的指针”类型的prvalue,其中T是一个对象类型,cv2与cv1具有相同的cv资格,或者比cv1具有更高的cv资格。如果原始指针值表示内存中某个字节的地址A,而A不满足T的对齐要求,则结果指针值是未指定的。否则,如果原始指针值指向一个对象a,并且有一个类型为T(忽略cv-qualification)的对象b可以与a进行指针相互转换,则结果是指向b的指针,否则,指针值不会因转换而改变。
我想知道,转换是否是指针可转换的有什么区别?有没有一种情况,当将void*
转换为指针可转换的东西时,指针值实际上会发生变化?这种区分的目的是什么?
对于完整性指针互换:
在以下情况下,两个对象 a 和 b 是指针互转换的:
如果两个对象是指针可相互转换的,那么它们有相同的地址,并且有可能通过reinterpret_ cast从指向另一个对象的指针获得指向一个对象的指针。
有没有一种情况,当将空洞*投射到指针可互换的东西实际上会改变指针值时?
不,标准明确规定
如果两个对象是指针可交换的,则它们具有相同的地址
这种区别的目的是什么?
我认为区别不在于指针的值,而在于它的语义。重要的部分是,你最终会得到一个指向对象b
的指针(它与原始对象指向的可以互换)。这是比“原始值保持不变”更强大,更具体的保证,即使在这种情况下原始值也保持不变。
更强的保证:生成的指针指向实际对象(而不仅仅是内存中的地址)
更具体的保证:指定了这个对象:它是对象b
,指针可以与指针指向的原始对象互换。
你可能误解了“指针值”这个术语。该术语在[basic.compound]/3中定义:
指针类型的每个值都是以下值之一:
>
指向对象或函数的指针(该指针称为指向对象或函数),或
超过对象末尾的指针 ([expr.add]),或
该类型的空指针值 ([conv.ptr]),或者
无效的指针值。
指针类型的值(即指向或经过对象末尾的指针)分别表示对象占用的内存中的第一个字节 ([intro.memory]) 或对象占用的存储结束后内存中的第一个字节的地址。
所以你可以看到标准中的术语“指针值”是一个非常抽象的术语。即使两个指针值代表同一个地址,它们也可能有不同的值。cppreference中的例子很好地演示了“指针值”的概念:
struct S1 { int a; } s1;
struct S2 { int a; private: int b; } s2; // not standard-layout
union U { int a; double b; } u = {0};
int arr[2];
int* p1 = reinterpret_cast<int*>(&s1); // value of p1 is "pointer to s1.a" because s1.a
// and s1 are pointer-interconvertible
int* p2 = reinterpret_cast<int*>(&s2); // value of p2 is unchanged by reinterpret_cast and
// is "pointer to s2".
int* p3 = reinterpret_cast<int*>(&u); // value of p3 is "pointer to u.a": u.a and u are
// pointer-interconvertible
double* p4 = reinterpret_cast<double*>(p3); // value of p4 is "pointer to u.b": u.a and u.b
// are pointer-interconvertible because both
// are pointer-interconvertible with u
int* p5 = reinterpret_cast<int*>(&arr); // value of p5 is unchanged by reinterpret_cast and
// is "pointer to arr"
指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int *、double *、char * 等。 如果一个指针指向的是另外一个指针,我们就称它为 二级指针,或者 指向指针的指针。 假设有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量,它们的关系如下图所示: 将这种关系转换为C语言代码: 指针变
6. 指向指针的指针与指针数组 指针可以指向基本类型,也可以指向复合类型,因此也可以指向另外一个指针变量,称为指向指针的指针。 int i; int *pi = &i; int **ppi = π 这样定义之后,表达式*ppi取pi的值,表达式**ppi取i的值。请读者自己画图理解i、pi、ppi这三个变量之间的关系。 很自然地,也可以定义指向“指向指针的指针”的指针,但是很少用到: int
指向指针的指针是多个间接或指针链的形式。 通常,指针包含变量的地址。 当我们定义指向指针的指针时,第一个指针包含第二个指针的地址,它指向包含实际值的位置,如下所示。 必须声明一个指向指针的指针的变量。 这是通过在其名称前面放置一个额外的星号来完成的。 例如,以下是声明指向int类型指针的指针的声明 - int **var; 当目标值由指针指向间接指向时,访问该值需要应用星号运算符两次,如下例所示
指向指针的指针是多个间接或指针链的形式。 通常,指针包含变量的地址。 当我们定义指向指针的指针时,第一个指针包含第二个指针的地址,它指向包含实际值的位置,如下所示。 必须声明一个指向指针的指针的变量。 这是通过在其名称前面放置一个额外的星号来完成的。 例如,以下是声明指向int类型指针的指针的声明 - int **var; 当目标值由指针指向间接指向时,访问该值需要应用星号运算符两次,如下例所示
指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位编译器指针大小为4字节,64位编译器指针大小为8字节),但是,任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。 int a = 100; int *p; p = a; //把a的值赋值给指针变量p
我正在学习链表,以及如何在C中使用结构和指针创建链表。下面我举一个例子。据我所知,被调用的将头节点所在的结构的开始内存位置作为参数传递。push()函数的参数将结构节点作为指向指针的指针,因此它作为引用传递,而不是实际副本。因此,我们的的第一个指针只是指向头部节点的内存位置的指针,第二个指针指向该值,该值是头部节点指向的下一个内存位置。我们通过为结构节点分配一些内存,在结构节点内创建一个名为new