【问题标题】:Casting a pointer as lvalue将指针转换为左值
【发布时间】:2020-04-20 18:27:58
【问题描述】:

为什么(int*) p = &x; 不是有效语句? 而*(int*) p = &x; 是没有警告的有效声明? 我知道强制转换是rvalue,但是第二条语句是如何编译的却没有警告?

【问题讨论】:

  • 在第二种情况下你有一个左值。
  • 你是如何声明x的?
  • p 是如何定义的?该代码对我来说似乎很可疑。
  • 在不知道所涉及的类型的情况下无法回答。 ...尽管如此,这并没有阻止 3 个人回答。

标签: c pointers casting rvalue lvalue


【解决方案1】:
(int*) p = &x;

这是无效的,因为强制转换的结果不是左值。它只是一个表达式,其类型是强制转换中指定的类型。

*(int*) p = &x;

这是有效的,因为解引用运算符* 的结果是一个左值。取消引用指针会为您提供指针指向的对象。

【讨论】:

  • *(int **)&p = &x;:D
【解决方案2】:

直观地说,左值是一个表示“这是一个诚实的对象”的表达式,而右值是一个表示“这是一个不是对象的值”的表达式。 (区别比这有点模糊,但现在它是一个合理的简化。)也就是说,左值是一个可以放入东西的盒子,而右值只是盒子里的值。

例如,表达式137 是一个右值,因为它是一个纯数字,而不是一个包含数字的框。如果x 是一个变量,那么表达式x 是一个左值,因为它代表了盒子和其中的数字,但表达式x + 137 是一个右值,因为它只代表一个数字,而不是一个包含一个号码。

演员表是如何影响这个因素的?假设xint。那么(float)x 是一个右值,因为它纯粹代表一个值——具体来说,它是“如果你采用x 并做了最不可怕的事情来表示它为float,你会得到的数字。”这不是一个可以放东西的盒子。

这就是原因

(int *)p = &x;

不起作用。 (int *)p 是一个右值——一个纯值,不是你可以分配给它的东西——你试图把它当作一个可以放东西的盒子。

另一方面,指针解引用的结果是一个左值,因为它表示“往那边看!这是一个你可以放东西的盒子”。所以从这个意义上说,你可以写

*(int *)p = x;

因为这意味着

  1. 计算表达式(int *)p。好的,我们现在有了一个右值,它是一个指向内存中某个位置的指针,其中包含一个 int
  2. 取消引用该指针以获取*(int *)p。好的,我们现在有了一个左值,代表那个整数。
  3. x 填入该位置。没关系 - *(int *)p 是一个盒子。

不过,这段代码可能还有其他一些问题:

*(int *)p = &x;

这里,这个表达式的 RHS 类型为(int *),它是一个指针。此表达式的 LHS 具有 int 类型(您取消了指向整数的指针),因此您将指针转换为整数。所以这意味着要么缺少演员表,要么你用这段代码做错了事情。

第二个问题是

*(int *)p

意思是“解释p,好像它告诉你在内存中可以找到int,然后在那里写一些东西。”如果p 不是一个指针,这几乎肯定会让你的代码崩溃,因为你会在内存中随机写入某个地方。如果p 一个指针,那么也许最好转换&x,而不是p

p = (T*) &x;

其中Tp 指向的事物的类型。

【讨论】:

  • “如果 p 是一个指针,那么也许最好转换 &x,而不是 p?” 可能 p 是一个 void * 指针(当然抛开所有纠正对&x的疑虑)。
【解决方案3】:

技术术语有时会令人困惑,尤其是当读者不能很好地理解事物的工作原理时。

什么是左值?有地址的东西。 在第一种情况下,您有一个指针。在第二种情况下,您取消引用一个指针。

什么是指针?指针一个地址。地址本身没有地址(好吧,在这里我们不要太技术化)。在您的示例中,假设p 是常数1235。它的地址是什么?没有,它只是一个常数,它可能不存在于内存中。也许它在寄存器中。也许编译器完全优化了它。 此外,您的表达式是(int*)p = &x 说“获取地址 1235 并为其分配 x 的地址,可能类似于 6789”。换句话说,“将地址 1235 更改为 6789”。什么?!换个地址?!

什么是解引用指针?它是指针的内容,即指针指向的地址处的。现在,根据定义,有一个地址!这就是第二个声明中发生的事情。意思是“将p指向的地址的内容设置为&x”。所以在我的例子中它说“将内存地址1235的值设置为6789”。现在这是有道理的!这就是它是左值的原因。

我希望这是有道理的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 2012-10-24
    • 2017-02-12
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    相关资源
    最近更新 更多