简体   繁体   English

在一行中压缩分配和错误检查有什么好处?

[英]What are the advantages of squashing assignment and error checking in one line?

This question is inspired by this question , which features the following code snippet. 此问题的灵感来自此问题 ,其中包含以下代码段。

int s;
if((s = foo()) == ERROR)
    print_error();

I find this style hard to read and prone to error (as the original question demonstrates -- it was prompted by missing parentheses around the assignment). 我发现这种风格难以阅读并且容易出错(正如原始问题所示 - 它是由于在作业周围缺少括号而引起的)。 I would instead write the following, which is actually shorter in terms of characters. 我会写下面的内容,实际上字符更短。

int s = foo();
if(s == ERROR)
    print_error();

This is not the first time I've seen this idiom though, and I'm guessing there are reasons (perhaps historical) for it being so often used. 这不是我第一次看到这个成语,我猜这里经常使用的原因(也许是历史的)。 What are those reasons? 这些原因是什么?

I think it's for hysterical reasons, that early compilers were not so smart at optimizing. 我认为这是出于歇斯底里的原因,早期的编译器在优化方面并不那么聪明。 By putting it on one line as a single expression, it gives the compiler a hint that the same value fetched from foo() can be tested rather than specifically loading the value from s . 通过将它作为单个表达式放在一行上,它为编译器提供了一个提示,即可以测试从foo()获取的相同值,而不是专门从s加载值。

I prefer the clarity of your second example, with the assignment and test done later. 我更喜欢你的第二个例子的清晰度,稍后完成作业和测试。 A modern compiler will have no trouble optimizing this into registers, avoiding unnecessary loads from memory store. 现代编译器可以将其优化为寄存器,避免内存存储中不必要的负载。

When you are writing a loop, it is sometimes desirable to use the first form, as in this famous example from K&R: 在编写循环时,有时需要使用第一种形式,如K&R中这个着名的例子:

int c;

while ((c = getchar()) != EOF) {
    /* stuff */
}

There is no elegant "second-form" way of writing this without a repetition: 在没有重复的情况下,没有优雅的“第二种形式”写作方式:

int c = getchar();

while (c != EOF) {
    /* stuff */
    c = getchar();
}

Or: 要么:

int c;

for (c = getchar(); c != EOF; c = getchar()) {
    /* stuff */
}

Now that the assignment to c is repeated, the code is more error-prone, because one has to keep both the statements in sync. 现在重复了对c的赋值,代码更容易出错,因为必须保持两个语句同步。

So one has to be able to learn to read and write the first form easily. 因此,必须能够学会轻松地阅读和编写第一个表格。 And given that, it seems logical to use the same form in if conditions as well. 鉴于此,在if条件下使用相同的形式似乎也是合乎逻辑的。

I tend to use the first form mostly because I find it easy to read—as someone else said, it couples the function call and the return value test much more closely. 我倾向于使用第一种形式,因为我觉得它很容易阅读 - 正如别人所说,它更接近于函数调用和返回值测试。

I make a conscious attempt at combining the two whenever possible. 我尽可能地有意识地将两者结合起来。 The "penalty" in size isn't enough to overcome the advantage in clarity, IMO. IMO的“惩罚”规模不足以克服清晰度的优势。

The advantage in clarity comes from one fact: for a function like this, you should always think of calling the function and testing the return value as a single action that cannot be broken into two parts ("atomic", if you will). 清晰度的优点来自于一个事实:对于这样的函数,你应该总是考虑调用函数并将返回值测试为单个动作,不能分成两部分(“原子”,如果你愿意的话)。 You should never call such a function without immediately testing its return value. 如果不立即测试其返回值, 就不应该调用这样的函数。

Separating the two (at all) leads to a much greater likelihood that you'll sometimes skip checking the return value completely. 将两者分开(根本)会导致您有时更不可能完全跳过检查返回值。 Other times, you'll accidentally insert some code between the call and the test of the return value that actually depends on that function having succeeded. 其他时候,你会不小心在调用和返回值的测试之间插入一些代码,这些代码实际上取决于成功的函数。 If you always combine it all into a single statement, it (nearly) eliminates any possibility of falling into these traps. 如果你总是将它全部组合成一个语句,它(几乎)消除了落入这些陷阱的任何可能性。

I would always go for the second. 我总是会去第二个。 It's easier to read, there's no danger of omitting the parentheses around the assignment and it is easier to step through with a debugger. 它更容易阅读,没有遗漏分配周围括号的危险,并且使用调试器更容易。

I often find the separation of the assignment out into a different line makes debugger watch or "locals" windows behave better vis-a-vis the presence and correct value of "s", at least in non-optimized builds. 我经常发现将赋值分离到不同的行使得调试器监视或“本地”窗口相对于“s”的存在和正确值表现得更好,至少在非优化构建中是这样。

It also allows the use of step-over separately on the assignment and test lines (again, in non-optimized builds), which can be helpful if you don't want to go mucking around in disassembly or mixed view. 它还允许在赋值和测试行上单独使用步进(同样,在非优化版本中),如果您不想在反汇编或混合视图中进行混乱,这可能会有所帮助。

YMMV per compiler and debugger and for optimized builds, of course. 当然,每个编译器和调试器的YMMV以及优化的构建。

I personally prefer for assignments and tests to be on different lines. 我个人更喜欢分配和测试在不同的行。 It is less syntactically complicated, less error prone, and more easily understood. 它在语法上更复杂,更不容易出错,也更容易理解。 It also allows the compiler to give you more precise error/warning locations and often makes debugging easier. 它还允许编译器为您提供更精确的错误/警告位置,并且通常可以使调试更容易。

It also allows me to more easily do things like: 它还允许我更轻松地执行以下操作:

int rc = function();

DEBUG_PRINT(rc);

if (rc == ERROR) {
    recover_from_error();
} else {
    keep_on_going(rc);
}

I prefer this style so much that in the case of loops I would rather: 我更喜欢这种风格,在循环的情况下我宁愿:

while (1) {
    int rc = function();
    if (rc == ERROR) {
        break;
    }
    keep_on_going(rc);
}

than do the assignment in the while conditional. while条件中的赋值。 I really don't like for my tests to have side-effects. 我真的不喜欢我的测试有副作用。

I often prefer the first form. 我经常喜欢第一种形式。 I couldn't say exactly why, but it has something to do with the semantic involved. 我不能确切地说出原因,但它与所涉及的语义有关。

The second style feels to me more like 2 separate operations. 第二种风格对我来说更像是两个独立的操作。 Call the function and then do something with the result, 2 different things. 调用函数,然后对结果做两件事。 In the first style it's one logical unit. 在第一种风格中,它是一个逻辑单元。 Call the function, save the temprary result and eventually handle the error case. 调用函数,保存temprary结果并最终处理错误情况。

I know it's pretty vague and far from being completely rational, so I will use one or the other depending on the importance of the saved variable or the test case. 我知道这很模糊,远非完全理性,所以我会根据保存变量或测试用例的重要性使用其中一个。

I believe that clarity should always prime over optimizations or "simplifications" based only on the amount of characters typed. 我认为,清晰度应始终优先于优化或“简化”,仅基于键入的字符数量。 This belief has stopped me from making many silly mistakes. 这种信念阻止了我犯了许多愚蠢的错误。

Separating the assignement and the comparison makes both clearer and so less error-prone, even if the duplication of the comparison might introduce a mistake once in a while. 即使比较的重复可能偶尔引入错误,分离分配和比较也使得更清楚且更不容易出错。 Among other things, parentheses become quickly hard to distinguish and keeping everything on one line introduces more parentheses. 除此之外,括号变得很难区分并且将所有内容保持在一行上会引入更多括号。 Also, splitting it up limits statements to doing only one of either fetching a value or assigning one. 此外,将其拆分限制语句只执行获取值或指定值之一。

However, if you expect people who will read your code to be more comfortable using the one-line idiom, then it is wide-spread enough not to cause any problems for most programmers. 但是,如果您希望阅读代码的人更习惯使用单行习语,那么它的广泛传播不会给大多数程序员带来任何问题。 C programmers will definately be aware of it, even those that might find it awkward. C程序员肯定会意识到它,即使是那些可能会觉得尴尬的程序员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM