编译c代码:错误:左值作为赋值的左操作数需要左值

时间:2011-05-04 05:37:44

标签: c

当我尝试在gcc 4.4.5上编译一些代码时,gcc在这一行遇到错误:

ORG(e) = DEST(a);

这两个宏定义为:

#define ORG(e) ((site_struct *) ODATA(e))
#define DEST(e) ((site_struct *) DDATA(e))

使用gcc 3.4.5在solaris上编译时没有问题。

我一直试图找出为什么它不会编译很长一段时间但无济于事。有人能指出我正确的方向吗?


来自评论:

ODATA和DDATA定义为:

#define ODATA(e) ((edge_struct *)((e)&0xfffffffcu))->data[(e)&3]
#define DDATA(e) ((edge_struct *)((e)&0xfffffffcu))->data[((e)+2)&3]

3 个答案:

答案 0 :(得分:5)

我发现很难相信你可以在Solaris上编译它。作业的左侧是演员表的结果。 C语言中的强制转换结果总是 rvalues 。您不能将任何内容分配给右值。这很简单没有意义。 Rvalues不是对象。它们不存储在内存中,这就是为什么尝试将任何内容分配给rvalue是没有意义的。这是C的一个非常基本的事实,这就是为什么我不相信你可以用任何C编译器编译它。

例如,此代码

int i;
(int) i = 5; /* ERROR */
由于代码无法编译的原因相同,

无法编译。

很难“指出你正确的方向”,因为你完全不清楚你想要做什么。该任务应该是什么意思?你为什么要在任务的两边进行演员表?

答案 1 :(得分:1)

您的ODATA()DDATA()宏评估为左值(这些宏中的强制转换是指向取消引用以获取左值的指针)。因此,需要弄清楚原始ORG()DEST()宏的作用是什么:

#define ORG(e) ((site_struct *) ODATA(e))
#define DEST(e) ((site_struct *) DDATA(e))

基本上它们采用ODATA()DDATA()宏生成的左值并将它们视为指针。 GCC 3.4.5的cast-as-lvalue语言扩展,在3.4.5中已弃用并在4.0中删除,如果转换的操作数是左值,则允许将转换的结果用作左值。我们可以通过执行我们自己的指针/地址操作和解除引用来模拟它。更改ORG()DEST()宏以获取ODATA()DDATA()宏生成的左值的地址,然后将该地址取消引用作为指向所需类型的指针。这应该在GCC 4.x中产生与您使用现有宏的GCC 3.4.5相同的结果:

#define ORG(e) (*((site_struct **) &(ODATA(e))))
#define DEST(e) (*((site_struct **) &(DDATA(e))))

我认为这应该产生与原始代码在GCC 3.4.5中相同的行为 - 可能这是该应用程序的正确行为。

几点说明:

  • 正如其他答案所提到的那样 - 这些宏是混乱的,应该尽快重构为更易于维护的东西。但有时候你必须务实并且让港口工作。
  • 我对ODATA()DDATA()宏做了一些小修改,将它们包含在parens中。我不确定是否有必要,因为->[]运算符具有非常高的优先级,但我对于没有完全括号的表达式宏感到偏执:

    #define ODATA(e) (((edge_struct *)((e)&0xfffffffcu))->data[(e)&3])
    #define DDATA(e) (((edge_struct *)((e)&0xfffffffcu))->data[((e)+2)&3])
    

答案 2 :(得分:0)

施法的结果是右值,而不是左值。 IOW,结果只是“原始”值,而不是作为值源的原始对象。

在你的案例中如何解决问题并不完全明显。特别是,在不知道ODATA(e)和DDATA(e)是什么/做什么的情况下,很难猜测如何从那里开始。

如果您尝试将一个结构分配给另一个结构,则可以执行以下操作:

*(site_struct *)a = *(site_struct *)b;

请注意,即使我们在赋值的两边都有强制类型转换,我们也不会尝试分配强制转换的结果 - 相反,我们正在转换指向正确类型的指针,然后取消引用该指针,并指定指针引用的对象。

编辑:好的,在扩展宏之后,我们最终得到类似的结果:

((site_struct *)((edge_struct *)((e)&0xfffffffcu))->data[(e)&3]) =
((site_struct *)((edge_struct *)((a)&0xfffffffcu))->data[((a)+2)&3]);

基于其纯粹的丑陋,我想我会尝试至少支持几个抽象层次,并试图找出所有这些的意图。这非常接近只写编码。虽然您已按要求提供了ODATA和DDATA的定义,但看起来这样做会花费更多 - 您需要仔细查看edge_struct的定义,并可能{{1}也是。您几乎必须弄清楚site_struct data成员edge_struct成员的含义。

总而言之,这看起来像是一个相当严重的逆向工程案例,而且几乎不可能预测需要检查和理解多少代码才能重写/更新它到你的位置。将从现代编译器中获得正确的结果。