【问题标题】:What happens when a casted pointer has an increment operator?当强制转换的指针具有增量运算符时会发生什么?
【发布时间】:2011-03-19 21:52:06
【问题描述】:

例如:

int x[100];
void *p;

x[0] = 0x12345678;
x[1] = 0xfacecafe;
x[3] = 0xdeadbeef;

p = x;
((int *) p) ++ ;

printf("The value = 0x%08x", *(int*)p);

编译上述代码会在带有 ++ 运算符的行上生成一个 lvalue required 错误。

【问题讨论】:

    标签: c++ c pointers compiler-construction programming-languages


    【解决方案1】:

    强制转换创建了一个int * 类型的临时指针。您不能增加临时值,因为它不表示存储结果的位置。

    在 C 和 C++ 标准中,(int *)p 是一个右值,大​​致表示只能出现在赋值右侧的表达式。

    另一方面,

    p 是一个左值,这意味着它可以有效地出现在赋值的左侧。只有左值可以递增。

    【讨论】:

    • 在 C++ 中,左值和右值与赋值关系不大。 array_name 是不能出现在赋值左侧的左值,std::string("hello") 是可以出现的右值。
    • @FredOverflow :是的,正确。顺便说一句,我添加了一个解决这些问题的答案。 :)
    【解决方案2】:

    表达式((int *) p) 将存储在变量p 中的指针视为指向int 的指针。如果您想将 变量 本身视为指向 int 变量的指针(然后递增它),请使用引用强制转换:

    ((int *&) p) ++ ;
    

    【讨论】:

    • 由于严格的别名冲突,这会导致未定义的行为
    【解决方案3】:

    感谢 larsmans 指出正确的方向。

    我冒昧地对此进行了深入研究。因此,为了将来参考,根据 C99 标准 (http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf) 的第 6.5.2.4 和 6.5.4 节:

    6.5.2.4 后缀递增和递减运算符

    约束

    后缀增量的操作数 或减量运算符应具有 合格或不合格的实物或 指针类型,并且应该是可修改的 左值
    ..
    ..
    6.5.4 转换运算符
    ..
    ..
    [脚注] 89) 演员表 不产生左值。于是,一个演员 到一个合格的类型有相同的 对不合格者的影响 类型的版本。

    注意:这仅适用于 C。C++ 可能会以不同的方式处理强制转换。

    【讨论】:

      【解决方案4】:

      你可以得到预期的结果

      p = (int*)p + 1;
      

      对指向p 的解引用指针(它是一个左值)使用增量运算符也可以:

      (*(int**)&p)++;
      

      但是,后者不可移植,因为(void*)p 的表示可能与(int*)p 不同。

      【讨论】:

      • 你的第一个建议是正确的;第二个是未定义的行为(严格的别名违规)
      【解决方案5】:

      右值表达式((int *) p) 创建一个int* 类型的临时表达式,不能在其上应用运算符++

      ++ 需要一个左值作为其操作数。

      正如@FredOverflow 提到的lvaluesrvalues 与分配关系不大。

      数组是左值,因为它们是不可修改的,所以它们仍然不能被赋值。 std::string("Prasoon") 是一个右值表达式,它仍然可以出现在赋值运算符的左侧,因为我们可以在临时对象上调用成员函数(在这种情况下为 operator =)。

      【讨论】:

      • 没有标量临时对象 :) 评估右值 ((int *) p) 的结果只是一个值。
      • @FredOverflow :我不认为“没有标量临时”这句话是 100% 正确的。对于const int& ref = int(),你有什么想说的吗?它不会创建一个标量临时变量吗?
      • int()0 相同,但你有一点:绑定到引用到常量可以隐式地创建一个标量临时。怎么样:“没有表达式的结果是一个标量临时。”
      • @FredOverflow : const int& ref = int() 作为一个整体是一个表达式,对吧?它可以创建一个标量临时。所以我对你的第二个陈述“没有......”也有问题。 :-)
      • @FredOverflow :标准是否明确说“你不能有一个标量临时”?我认为没有。
      猜你喜欢
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      • 1970-01-01
      相关资源
      最近更新 更多