C 将指针强制转换为左值

C 将指针强制转换为左值,c,pointers,casting,rvalue,lvalue,C,Pointers,Casting,Rvalue,Lvalue,为什么(int*)p=&x不是有效的语句? 而*(int*)p=&x是没有警告的有效语句吗? 我知道casting是rvalue,但是第二条语句是如何编译的,没有任何警告 (int*) p = &x; 这是无效的,因为强制转换的结果不是左值。它只是一个类型为强制转换中指定类型的表达式 *(int*) p = &x; 这是有效的,因为解引用运算符*的结果是左值。取消对指针的引用将为您提供指针指向的对象。直观地说,左值是一个表示“这是一个诚实的对象”的表达式,而右值是一个表示“这

为什么
(int*)p=&x不是有效的语句?
而
*(int*)p=&x是没有警告的有效语句吗?
我知道casting是rvalue,但是第二条语句是如何编译的,没有任何警告

(int*) p = &x;
这是无效的,因为强制转换的结果不是左值。它只是一个类型为强制转换中指定类型的表达式

*(int*) p = &x;

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

直观地说,左值是一个表示“这是一个诚实的对象”的表达式,而右值是一个表示“这是一个非对象的值”的表达式。(区别比这要模糊一些,但现在它是一个合理的简化。)也就是说,左值是可以放入某些内容的框,而右值只是框中的值

例如,表达式
137
是一个右值,因为它是一个纯数字,而不是一个包含数字的框。如果
x
是一个变量,则表达式
x
是一个左值,因为它同时表示框和其中的数字,而表达式
x+137
是一个右值,因为它只表示一个数字,而不是一个包含数字的框

你是如何理解这一点的?假设
x
是一个
int
。然后,
(float)x
是一个右值,因为它纯粹代表一个值——具体地说,它是“如果你取了
x
,并且做了尽可能不可怕的事情,将其表示为
float
”它不是一个可以放东西进去的盒子

这就是原因

(int *)p = &x;
不起作用
(int*)p
是一个右值-一个纯值,不是可以赋值的值-您试图将其视为可以放入的框

另一方面,指针解引用的结果是一个左值,因为它表示“看那边!这是一个可以放入内容的框。”因此,从这个意义上说,您可以编写

*(int *)p = x;
因为那意味着

  • 计算表达式
    (int*)p
    。好的,我们现在有一个右值,它是指向内存中某个地方的指针,其中包含
    int
  • 取消引用该指针以获取
    *(int*)p
    。好的,我们现在有一个左值,代表那个整数
  • x
    塞进那个地方。很好-
    *(int*)p
    是一个方框
  • 但是,此代码可能存在其他一些问题:

    *(int *)p = &x;
    
    这里,此表达式的RHS具有类型
    (int*)
    ,这是一个指针。此表达式的LHS的类型为
    int
    (您取消了对整数的引用),因此您正在将指针转换为整数。这意味着要么是缺少了一个演员阵容,要么是你用这段代码做了错事

    第二个问题是

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

    p = (T*) &x;
    

    其中
    T
    p

    所指的类型,技术术语有时会令人困惑,尤其是当读者不太了解事物的工作原理时

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

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

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


    我希望这是有意义的。

    在第二种情况下,您有一个左值。您是如何声明
    x
    ?如何定义
    p
    ?我觉得那个代码很可疑。不知道涉及的类型就无法回答。。。尽管如此,这并没有阻止3个人回答:D“如果p是指针,那么最好抛出&x,而不是p?”可能p是一个
    void*
    指针(当然,抛开对
    &x
    的所有正确怀疑)。