当前位置: 首页 > 知识库问答 >
问题:

static_cast指针值

羊舌墨一
2023-03-14

在当前的标准草案(和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 是指针互转换的:

    < li>(4.1)它们是同一对象,或者 < li>(4.2)一个是联合对象,另一个是该对象的非静态数据成员([class.union]),或者 < li>(4.3)一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则是该对象的任何基类子对象([class.mem]),或者 < li>(4.4)存在一个对象c,使得a和c是指针可相互转换的,c和b是指针可相互转换的。

如果两个对象是指针可相互转换的,那么它们有相同的地址,并且有可能通过reinterpret_ cast从指向另一个对象的指针获得指向一个对象的指针。

共有2个答案

壤驷喜
2023-03-14

有没有一种情况,当将空洞*投射到指针可互换的东西实际上会改变指针值时?

不,标准明确规定

如果两个对象是指针可交换的,则它们具有相同的地址

这种区别的目的是什么?

我认为区别不在于指针的值,而在于它的语义。重要的部分是,你最终会得到一个指向对象b的指针(它与原始对象指向的可以互换)。这是比“原始值保持不变”更强大,更具体的保证,即使在这种情况下原始值也保持不变。

更强的保证:生成的指针指向实际对象(而不仅仅是内存中的地址)

更具体的保证:指定了这个对象:它是对象b,指针可以与指针指向的原始对象互换。

邢冷勋
2023-03-14

你可能误解了“指针值”这个术语。该术语在[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 = &pi; 这样定义之后,表达式*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