6

我的疑问是关于Increment/Decrement运算符 ( ++and --) 在C(Also in C++) 中的使用。在程序中使用++和是绝对必要的吗?--例如考虑下面给出的代码,

int x=10;
x++; 

这可以很容易地替换如下,

int x=10;
x=x+1;

那么在实际编程中有必要使用++and吗?--我问这个是有特殊原因的。在我看来,它们是 中最令人困惑的运算符之一C,形成诸如*x++,等表达式++*xx++ + ++x并且每天会导致数千个错误。

当然我知道++和汇编指令之间的直接映射INCR是可能的。但我相信任何具有优化能力的体面编译器都可以替换x=x+1INCR x.

所以简而言之,我的问题是“有没有 x=x+1 不能替换 x++ 的情况? ”。

++如果有人可以提供一段在没有or时无法工作的代码,那可能会很有帮助--

有什么建议么?谢谢你。

4

7 回答 7

11

有什么情况是x = x + 1不能更换的x++

当然,foo(x = x + 1)不同于foo(x++)因为x = x + 1产生 的新值xx++产生 的旧值x


除此之外,没有太大的区别,而且严格来说++--不需要的(即,您可以使用而不是和代替来编写x += 1所有++x程序x -= 1--x

请注意,在 C++ 中operator++,andoperator--可以被重载,并且在操作迭代器时特别有用。

于 2013-05-19T13:34:55.993 回答
4

速记运算符(++、--、+=、-=、*= 等)的主要好处是您不需要重复操作数。这没什么大不了的

x = x + 1; 

很容易看出它x是同一个变量x。但是关于:

ptr->kerflunk->var.arr[x+y+z*w+i] = ptr->kerflunk->var.arr[x+y+z*w+i] + 1;

这与:

ptr->kerflunk->var.arr[x+y+z*w+i] = ptr->kerflunk->var.arr[x+y-z*w+i] + 1;

如果您在哪里看到:

ptr->kerflunk->var.arr[x+y+z*w+i]++;

在后一种情况下,很容易看出这是同一件事。

(是的,我正在做一个极端的例子,很可能通过对复杂结构的某些位使用一些临时变量等来改进它 - 但事实仍然是,使用的表达式++更容易看到“它增加了这个值")

我不认为 C 和 C++ 是好的初学者语言 - 不使用++,--+=,-=等来教授 C 和 C++ 的早期部分是完全可以的。只需使用x = x + 1.

[当然,如果你愿意,你仍然可以使用 C/C++ 来搞砸事情并且仍然是可以有效编译的东西:a[x = x + 1] = b[x = x + 1];在语法上是有效的,但也会产生与x++在两个序列点之间使用两次相同的问题]。

于 2013-05-19T14:04:09.347 回答
3

迭代器。

x = x + 1意味着可以将任何数字添加到 x,对于某些类型的 x 可能并非如此。

在迭代器的情况下。

前向迭代器只能递增,双向迭代器也可以递减,但不能向它们添加任何数字。从程序员的角度来看,它可能会强制执行有效的容器访问,因此您不会被诱惑使用std::list::begin() + 65536或其他东西。

另一方面,随机访问迭代器允许对迭代器进行算术运算。

- 编辑 -

是否绝对必要

没有语言功能是绝对必要的。

在 C++ 的情况下,您可以摆脱 stl、命名空间、类、预处理器、模板、局部变量、异常和函数调用,并且仍然可以生成可以执行某些操作的工作程序。当然,这个程序大部分是不可读的,编写它需要更长的时间,但这是可能的。基本上,您需要编程的只是 goto、数组、全局变量、从终端读取/写入字符的函数,仅此而已。其他一切在技术上都是可选的。

语言功能旨在让您的生活更轻松,而不是因为没有 htme 就无法生活。至于 ++/-- 运算符,它们似乎对于实现前向/双向迭代器和其他支持 prev/next 语义但不支持任意参数递增/递减的数据类型最有用。

于 2013-05-19T14:04:03.970 回答
1

这似乎是绝对必要的——有很多编程语言(FORTRAN、COBOL、Pascal、PL/I、ALGOL、Simula 等等)不包括任何直接模拟 C 的前/后- 递增/递减运算符。

也就是说,++x;x++;和之间有一个相当根本的区别x = x + 1;——后者对操作数进行两次评估,而前者对操作数仅进行一次评估。

在传递具有副作用的参数的宏的情况下,这会有所不同,并且您只希望这些副作用发生一次,而不是两次。但是,这方面的真实示例并不多,因为您只想评估一次的参数的明显示例(例如,参数本身类似于 )如果应用于它们(例如,)x++根本不会编译.++++x++

然而,这在 C++ 中略微放松,因为(例如)函数可以返回引用。只想调用该函数一次,然后递增它返回的结果至少是一种合理的可能性。是的,您可以通过其他方式来实现(例如,大多数 C++ 程序员更喜欢内联函数而不是宏),但这至少是一种可能性。

于 2013-05-19T13:40:20.533 回答
1

绝对没有必要……但请记住,C 不是计算机语言,它是一种编程语言,但仍然是人类语言……C 被认为是一种低级语言,但还有更多编译器可能产生的一种可能输出:

我++

它可以将值存储在寄存器中,然后递增,然后复制回堆栈,为依赖于iincr 之前的下一条语句递减该寄存器,并在下次使用该值时使用相同的寄存器。

它可能在 CIS 中使用一个助记符来增加堆栈上的值。

它可以制作 2 份副本,一份用于递增,一份用于返回...

这并不重要,因为 C 已经将它从你那里抽象出来,但它确实使代码更具可读性。

于 2013-05-19T14:34:19.510 回答
0

对于 C++,这比能力更有效,假设你有一个类型的对象xX它是类类型的对象

x = x + 1;

这涉及(x+1)添加并1返回xclass 的新副本X。然后这个新的临时的X被复制到x. 这可以在没有任何副本的情况下完成

++x;  

因为C我唯一能想到的就是方便。如果你正确使用它,它根本不会令人困惑。鉴于单个增量和减量是许多算法的重要组成部分,它有助于使意图清晰,而不是将其与“正常”加法或减法混淆。

于 2013-05-19T13:36:10.120 回答
0

简短的回答是,x = x + 1不能总是直接替换x++(就搜索和替换操作而言),但任何出现的x++都可以用不使用增量运算符的等效代码替换。

正如 rightfold 所写,对 的调用会f(x = x + 1)传递 的递增值x,而对 的调用f(x++)不会;但你可以很容易地用f(x); x = x + 1;.
您甚至可以使用x = (f(x), x + 1);,尽管这可能更难阅读。

增量运算符使在单行中分配和增加值变得容易,但您可以选择在使用值之前还是之后进行增量:

x = 1;
y = ++x;  // y = 2, x = 2
z = x++;  // z = 2, x = 3

对于像x = x + 1值这样的简单赋值,总是在增量发生后使用。

它在指针操作中特别有用。例如,您可以非常简洁地复制一个以 null 结尾的字符串:

while ((*dest++ = *src++) != '\0')
  ;

这是一个很常见的成语,有经验的程序员会立刻认出来并理解。所以这是一个非常方便的简写,但你总是可以扩展代码:

while (true) {
  *dest = *src;
  if (*dest == '\0') {
    break;
  }
  src + src + 1;
  dest + dest + 1;
}

尽管这给出了相同的结果,但阅读和理解需要付出更多的努力。事实上,我希望有经验的程序员会想知道为什么作者不只使用更简单的版本——是缺乏经验,还是有一些隐藏的差异?

于 2013-05-19T13:44:36.790 回答