C中递增/递减算子的必要性

时间:2013-05-19 13:28:04

标签: c++ c

我怀疑Increment/Decrement ++--运算符(CC++)的使用情况(同样在++中)。是否绝对有必要在程序中使用--int x=10; x++; ? 例如,考虑下面给出的代码,

int x=10;
x=x+1;

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

++

那么有必要在实际编程中使用--C吗?我是出于特殊原因问这个问题。在我看来,它们是*x++中最容易混淆的运算符之一,形成了++*xx++ + ++x++等表达式,每天都会导致成千上万的错误。

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

总之,我的问题是“是否存在x = x + 1无法替换x ++的情况?”。

如果有人可以提供一段在--或{{1}}没有的情况下无效的代码,那可能会非常有用。

有什么建议吗?谢谢。

7 个答案:

答案 0 :(得分:11)

  

是否存在x = x + 1无法替换x++的情况?

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


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

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

答案 1 :(得分:4)

速记运算符(++, - ,+ =, - =,* =等)的主要好处是您不需要重复操作数。这对

来说没什么大不了的
x = x + 1; 

很容易看出xx是同一个变量。但是怎么样:

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 ++的早期部分是完全没问题的,{ {1}}等。只需使用-=即可。

[当然,如果你愿意的话,你仍然可以使用C / C ++搞砸了,仍然可以有效地编译:{{1​​}}在语法上是有效的,但也会产生同样的问题在两个序列点之间使用x = x + 1两次]。

答案 2 :(得分:3)

迭代。

x = x + 1表示任何号码都可以添加到x中,某些类型的x可能不是这种情况。

如果是迭代器。

Forward iterators只能递增,bidirectional iterators也可以递减,但您不能为它们添加任何数字。从程序员的角度来看,它可能会强制实施有效的容器访问,因此您不会想要使用std::list::begin() + 65536或其他东西。

另一方面,

Random access iterator允许对迭代器进行算术运算。

- 编辑 -

  

绝对必要

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

在C ++的情况下,您可以摆脱stl,名称空间,类,预处理器,模板,局部变量,异常和函数调用,并且STILL会生成可以执行某些操作的工作程序。当然,这个程序几乎是不可读的,编写它需要更长的时间,但这是可能的。基本上你需要编程的是goto,数组,全局变量,从/到终端读/写字符的功能,就是它。 Everything else is technically optional

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

答案 3 :(得分:1)

似乎非常怀疑它是绝对必要的 - 有很多编程语言(FORTRAN,COBOL,Pascal,PL / I,ALGOL,Simula等等)不包含任何与C的预先直接类比 - /后递增/递减运算符。

也就是说,++x;x++;x = x + 1;之间存在一个相当根本的区别 - 后者对操作数进行两次计算,前者只评估操作数一次。

如果您传递的是具有副作用的参数,那么这会产生影响,您只希望这些副作用发生一次,而不是两次。尽管如此,没有太多真实的例子,因为大多数明显的参数示例你只想评估一次(例如,参数本身就像x++)只是赢了如果您将++应用于他们(例如++x++),则需要编译。

这在C ++中略有松动,但是,(例如)函数可以返回引用。想要只调用一次函数,然后递增它返回的结果至少是合理的可能性。是的,您可以采用其他方式(例如,大多数C ++程序员更喜欢内联函数到宏),但这至少是一种可能性。

答案 4 :(得分:1)

绝对没有必要......,但是记住C不是一种计算机语言,它是一种编程语言,但仍然是一种人类...... C被认为是一种低级语言,但有编译器可以通过以下方式生成多个可能的输出:

我+ +

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

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

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

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

答案 5 :(得分:0)

对于C ++而言,这更多的是效率而不是功能,假设您具有类型x的对象X,它是类类型对象

x = x + 1;

这涉及(x+1),它将1添加到x并返回类X的新副本。然后,X的这个新临时副本将复制到x。这可以通过

完成任何副本
++x;  

对于C,我唯一能想到的是便利性。如果你使用它,它根本不会混淆。鉴于单个递增和递减是许多算法的基本部分,它有助于使意图清晰,而不是将其与“正常”加法或减法混淆。

答案 6 :(得分:0)

简短的回答是x = x + 1不能总是直接替换x++(就搜索和替换操作而言),但x++的任何出现都可以替换为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

使用while ((*dest++ = *src++) != '\0') ; 之类的简单赋值,增量后,总是使用

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

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

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

{{1}}

虽然这给出了相同的结果,但阅读和理解需要花费更多的精力。事实上,我希望一位经验丰富的程序员想知道为什么作者不只是使用更简单的版本 - 它缺乏经验,还是有一些隐藏的差异?