2012-02-15 113 views
1

请帮我解决这个问题。接下来的步骤是表达式是:增量,增量前和增量后

//Expression 
offSpring1[m1++] = temp1; 

//步骤:

1.-增量M1

2:分配temp1中给后代

我一直认为括号内的表达是第一个要完成的。但现在我很困惑。因此,如果这样写:

//Expression 
offSpring1[++m1] = temp1; 
//Steps would be: 

1.- assign temp1 to offSpring 
2.- increment m1 

如果步骤将是相同的第一批,是有什么差别我++和++我?

回答

7
int i = 0; 
std::cout << i++ << std::endl; 
std::cout << i << "\nreset" << std::endl; 
i = 0; 
std::cout << ++i << std::endl; 
std::cout << i << std::endl; 

输出:

0 
1 
reset 
1 
1 

i++返回值,因为它目前矗立在表达,那么递增变量。 ++i将增加变量,然后返回当前表达式中使用的值。

+1

酷男!好例子。谢谢 – Guido 2012-02-15 17:24:48

0

offSpring1[m1++] = temp1;不会做你说的。

  1. 赋值temp_m1 = m1。
  2. 递增m1。
  3. 索引offSpring1[temp_m1]
  4. temp1分配为索引值。

在另一方面offSpring1[++m1] = temp1;是这样工作的:

  1. 增量M1。
  2. 索引offSpring1[m1]
  3. temp1分配为索引值。
+0

但是第2步可能发生在第4步之前或之后(在第一种情况下),我认为根据C++ 11规则,'m1'本身可能不会在'offSpring'之后被改变(虽然使用的索引是新值,它可能尚未存储回'm1')。 – 2012-02-15 17:25:54

+0

@BenVoigt对“offSpring”和“m1”的修改是副作用。没有中间顺序点(使用C++ 03的语言),所以它们的发生顺序是未指定的。 (就此而言,如果'offSpring [m1]'碰巧指的是'm1',那么行为将会是不确定的。) – 2012-02-15 17:41:53

+0

@James:这正是我想要做的。你能否在我的回答中检查我是否正确解释了它? – 2012-02-15 17:42:57

3
offSpring1[m1++] = temp1; 

offSpring1[m1] = temp1; 
m1 += 1; 

offSpring1[++m1] = temp1; 

m1 += 1; 
offSpring1[m1] = temp1; 
1

只要运行这两种不同的测试方案理解上的差异在后增量和增量预算

对于之间++ I(预增量)

int main() 
{ 
    int* offSpring = calloc(20,sizeof(int)); 
    int m1 =1; 
    offSpring[++m1] = 10; 
    printf("%d,%d",offSpring[m1],m1); 
} 

在第一个你将得到10作为后代的值[M1]。 为什么?因为这是预增加运算符,这意味着首先m1得到增加,其余的得到评估。

对于i ++(后增量)

int main() 
{ 
    int* offSpring = calloc(20,sizeof(int)); 
    int m1 =1; 
    offSpring[m1++] = 10; 
    printf("%d,%d",offSpring[m1],m1); 
} 

在第二,因为递增运算符使用,你会得到一个0值,因为你是第一分配10到后代[M1],然后m1得到增加。

+0

使用未指定行为的示例非常糟糕,因为在两种情况下都可能获得'10'。 – 2012-02-15 17:28:37

+0

是不是很遥远得到10?我的意思是我在调试代码时从未遇到过非常大的值或0。但是,当然你是正确的,为了这个例子是完整的,我将编辑答案 – Lefteris 2012-02-15 17:30:28

0

第一个的描述是第二个的正确描述。第一个的正确描述非常相似,您只需要在其他之前添加“复制当前值m1”步骤。

但是,如果m1具有原始类型,那么在这里确实缺少序列点。规则在C++ 03和C++ 11之间有所变化。

如果m1有一个用户定义的类型,那么涉及影响排序的函数调用。


此代码

offSpring1[m1++] = temp1; 

执行以下(如果m1是基本类型):

auto const old_m1(m1); 
auto const new_m1(old_m1 + 1); 
auto& lhs(offSpring[old_m1]); 
parallel { lhs = temp1; m1 = new_m1; } 

此代码

offSpring1[++m1] = temp1; 

正是不同之处在于同一lhs绑定使用new_m1而不是old_m1

无论哪种情况,在m1之前或之后是否写入lhs都未指定。

如果m1不是原始类型,它看起来更像:

auto const& index = m1.operator++(0); // one argument 
auto& lhs = offSpring.operator[](index); 
lhs = temp1; 

VS

auto const& index = m1.operator++(); // no arguments 
auto& lhs = offSpring.operator[](index); 
lhs = temp1; 

在这两种情况下,改变m1在写lhs之前肯定做。

+0

本,谢谢你的详细解释。 – Guido 2012-02-15 18:50:10

0

即使后缀增量是您的第一个示例中第一个要评估的值,它的值是要递增的变量的原始值。

offSpring1[m1++] = temp1; 

因此,即使M1为阵列idexing之前递增,的temp1值在m1 - 1位置分配。

0

它的工作原理正是你所描述的相反:

offSpring1[m1++] = temp1相同 offSpring[m1] = temp1; m1 = m1 + 1;

OffSpring1[++m1] = temp1相同 m1 = m1 + 1; OffSpring1[m1] = temp1;

前缀符号的增量计算表达式 后缀表示法之前在评估表达式后递增

+0

不,这是不一样的。您的“等效”版本有更多的序列点。 – 2012-02-15 17:29:05

1
  • j = ++i相同i = i+1; j = i;
  • j = i++相同j = i; i = i+1;
0

有两个方面的表达式(或子表达):它的​​价值, 和其副作用。 i ++的值是i的值; ++ i的 值为i + 1,转换为i的类型。 这是表达式中使用的值。两者的副作用是 增加变量i。这可能发生在 前面的顺序点之后和下一个之前的任何时间。假设i是一个全局变量 ,你写的东西,如:

i = 0; 
f()[i ++] = g(); 
f()[++ i] = g(); 

标准只字未提的i值是否在f()g()看到的是,在增量之前或之后。在任何情况下。 所有的标准都说增量效应将在完整表达式开始之后(但可能作为完整表达式的第一件事)发生,并且在结束之前发生 。 (这 他们不会用一个函数调用交错,因此,如果f() 读取i两次,可以保证它看到相同的值。)

0

不幸的是,在那些2个的代码片断您已经发布有,没有保证评估的顺序。如果你的表情不合适,可能会发生或多或少的事情。

要开始与++和之间的差++一个:

  • 一个++将递增一个,但使用它将会看到增量
  • ++一个将递增一个之前的值的表达式,而使用它的表达式会看到递增的值。
  • 列表项

buffer[a++] = b; 

编译器可以决定做++在表达式中的任何一点。因此,如果'b'实际上是涉及a的表达式,则可以在不同的编译器上得到不同的结果。以下两项都是有效的:

  • 得到a的值;
  • 增量的
  • 工作出其中缓冲液[旧值]指向
  • 对b求值
  • 商店B

或该

  • 评估B;
  • 锻炼,其中缓冲液[一个]指向
  • 商店B
  • 增量的

如果“B”应该发生在涉及那些2个实施方式中会产生不同的结果。两者都是有效的。