在C源代码中返回到无处(?)

5

来看一下下面的代码。

"Hello " "World!";
"The number is ", 37;
int x=23;
char *y="232";
x,x+2,x*3;
atoi(y) - x;

这是一个完全有效的C(99)源代码片段。 但是!所有这些表达式都没有返回值! 如何跟踪或使用所有这些匿名值? 它们存储在哪里,有什么目的?


3
仅适用于C99,不适用于C89。 - Paul R
如果你要混合汇编语言和C语言,这些可能有一些用处,但我怀疑它们的实用性。 - Will A
3
@John Weldon,@Paul R,@Piskvor,@progrmr,@Jon Cage:这个问题怎么可能不被合理地回答呢?我认为Forrest和其他人都非常出色,给出了有意义和有帮助的答案。 - Dirk Vollmar
Paul R 简直是错的。这是有效的 C99。 - R.. GitHub STOP HELPING ICE
我的错。他编辑了它还是我在发布之前读了3或4次,读反了呢?啊,抱歉。 - R.. GitHub STOP HELPING ICE
显示剩余3条评论
7个回答

8

这些值没有任何作用,您无法检索它们。实际上,大多数值被编译器优化掉了。

整个片段可以简化为 atoi("232") ,因为函数调用通常不能被优化掉。


1
atoi 在 C 标准中被定义为没有副作用的方式,因此一个好的编译器也会将其优化掉。(在程序中重新定义 atoi(具有外部链接)的行为是未定义的,因此只要当前文件范围内没有静态定义,编译器就可以自由地假设它没有被重新定义。) - R.. GitHub STOP HELPING ICE

4

那些特定的表达式是无用的。另一方面,这是被允许的,因为有些表达式具有副作用(也许有返回值),有时只需要副作用。


2
你是在询问这个是否是这样的吗:
int main() {
   1;
}

这段代码是否合法?如果是,那么它一直都是合法的。


2
即使在函数结尾没有 return 语句,这段代码是否有效?我知道大多数编译器会勉强接受,但我认为在任何函数结尾都不返回(除了 C++ 中的 main 函数)是不严格有效的。 - Chris Lutz
1
@Chris Sigh。我的观点是关于表达式1,而不是main函数的返回值。 - anon
1
我非常确定,不明确从main返回一直是有效的。 - Puppy
2
@DeadMG - 不是的。在C++和更近期的C99中,它被允许作为一个缺陷存在,但在那之前它从未成为标准C的一部分。@Neil - 很抱歉这么迂腐。我理解你的观点,但担心(可能是不必要的)它可能会有点误导性。 - Chris Lutz

2

没有副作用的表达式并不特别有用。通常你会在这些地方找到一个函数调用,而函数体实际上会导致程序中的某些状态改变。

语言中有很多愚蠢的方法来什么都不做。考虑C语言语句:

  ;

它什么也不做。


2
每次调用printf(3)时,如果没有检查其返回值,就会发生相同的情况,返回值将被丢弃。尽管函数调用可能具有副作用(printf(3)肯定有副作用),因此仍会生成执行它的指令。大多数现代编译器将删除您列出的大多数语句,只要给定适当的优化标志即可。如果您真的想看到会发生什么,请使用(例如-O2)和不使用优化的选项将您的源代码编译为汇编,并跟踪指令。

不完全相同,因为printf具有(可以说是有用的)副作用。问题中的任何示例都没有副作用。 - R.. GitHub STOP HELPING ICE

1
逗号运算符按顺序计算表达式并返回最后一个的值。如果前面的表达式执行副作用(如赋值),它才有用。
据我所知,在这里使用逗号是多余的,表达式的值被丢弃了 - 无法检索它们。除非您在特殊的C解释器上下文中编写这些行...?

@Owen S. "特殊的C解释器"?你是什么意思?我的解释器使用C语法,但按照我定义的方式评估表达式? - Rizo
1
我不确定“返回最后一个值”的意思。我进行了一些测试,似乎不是这样的:y=0; x = ++y, y, ++y, y 在我的测试中将1分配给x(当然,在最后y为2)。 - ShinTakezou
@Rizo:是的,这样的东西存在,但据我所知并没有被广泛使用。解释器可能能够对这些语句进行一些传统 C 编译器无法完成的操作。 - Owen S.
@Shin:写出“x = (++y, y, ++y, y);”并查看结果。 - Owen S.
@Owen S,明白了!但是标准怎么说呢?逗号运算符a, b是简单的还是它应该总是(a, b)...那么a, b是什么,为什么a, b, c(a, b, c)不同呢?幸运的是我从来没有使用过,(也许只是在for中“无意识”地使用了)!! - ShinTakezou
1
@Shin:它只是"a,b",但是“,”的优先级低于“=”,因此如果你想利用“,”的这个特性,需要使用括号。不过这是古怪的C语法。我从未有过使用“,”这种方式的情况。 - Owen S.

1
从功能的角度来看,所有这些表达式的结果都已经丢失了。如果有良好的优化工作,它们根本不会计算。但是让我们假设它们正在计算。在这种情况下,“结果”可用的位置取决于编译器如何转换代码,这可以被认为是不可预测的事实。
在x86机器上,您可以认为整数结果和指针结果存储在eax中(然后将被删除),但这只是一种假设;如果对于特定的编译器和代码而言是真实的,那么对于另一个编译器或者如果您稍微更改了代码,可能就不是真实的了。也可能发生这样的情况:值被推到堆栈上,然后再次增加,因此,在重复使用之前,您可以在堆栈上找到该值。与eax相关的同样的论点也可以做出。
通过逗号连接的部分有所不同。像a,b这样的东西被读作“执行a,丢弃任何结果,然后执行b”,因此a的结果“从定义上”已经丢失了(当然,查看汇编代码时,您也可以在这种情况下发现它仍然可用,但很可能在评估b之后确实不再可用)。

抱歉,我不明白:a 的结果仍然在 b 中可用吗? 在哪里可以找到有关逗号运算符的更多信息? - Rizo
1
@Rizo转换成标准语言,我相信有人知道在哪里可以下载。如前所述,在a,b中,首先计算a并丢弃(丢失)结果(如果有的话),然后计算b并取得结果。例如,x = a,b;计算a,然后将b的评估结果分配给x。如果a对于b没有副作用,则可以编写x = b; a;a; x = b - ShinTakezou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接