에 차이가 ++i
와 i++
A의 for
루프는? 그것은 단순히 구문 일입니까?
에 차이가 ++i
와 i++
A의 for
루프는? 그것은 단순히 구문 일입니까?
답변:
a ++는 postfix로 알려져 있습니다.
a에 1을 더하고 이전 값을 반환합니다.
++ a는 접두사로 알려져 있습니다.
a에 1을 더하고 새로운 값을 반환합니다.
씨#:
string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
Console.WriteLine(++i);
}
Console.WriteLine("");
i = 0;
foreach (string item in items)
{
Console.WriteLine(i++);
}
산출:
1
2
3
4
0
1
2
3
foreach
그리고 while
루프는 사용하는 증가 유형에 따라 달라집니다. 아래와 같은 for 루프를 사용하면 i의 반환 값을 사용하지 않으므로 아무런 차이가 없습니다.
for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }
012 34
012 34
평가 된 값이 사용되면 증분 유형이 중요해집니다.
int n = 0;
for (int i = 0; n < 5; n = i++) { }
사전 증가 ++ i 는 i의 값을 증가시키고 새로운 증가 된 값으로 평가합니다.
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );
증가 후 i ++ 는 i의 값을 증가시키고 증가하지 않은 원래 값으로 평가합니다.
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
C ++에서는 일반적으로 사전 증분이 선호됩니다.
사후 증가를 사용하는 경우 컴파일러에서 추가 임시 변수를 작성하는 코드를 생성해야 할 수 있기 때문입니다. 이는 증가하는 변수의 이전 값과 새 값을 평가중인 표현식의 다른 곳에 필요할 수 있기 때문에 어딘가에 보유해야하기 때문입니다.
따라서 C ++에서는 적어도 사용할 선택을 안내하는 성능 차이가있을 수 있습니다.
이것은 증가되는 변수가 재정의 된 ++ 연산자를 사용하는 사용자 정의 유형 인 경우 주로 문제입니다. 기본 유형 (int 등)의 경우 성능 차이가 없습니다. 그러나 증분 후 연산자가 반드시 필요한 경우가 아니라면 증분 사전 연산자를 지침으로 고수하는 것이 좋습니다.
여기에 더 많은 토론이 있습니다 :
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm
C ++에서 STL을 사용하는 경우 반복자와 함께 for 루프를 사용하고있을 수 있습니다. 이들은 주로 ++ 연산자를 재정의 했으므로 사전 증가를 고수하는 것이 좋습니다. 컴파일러는 항상 더 똑똑해지며, 최신 컴파일러는 성능 차이가 없음을 의미하는 최적화를 수행 할 수 있습니다. 특히 증가하는 유형이 헤더 파일에 인라인으로 정의 된 경우 (STL 구현이 자주있는 경우) 컴파일러가 이 방법은 구현 된 다음 수행하기에 안전한 최적화를 알 수 있습니다. 그럼에도 불구하고 루프가 여러 번 실행되기 때문에 여전히 사전 증분을 고수 할 가치가 있으며, 이는 약간의 성능 저하가 곧 증폭 될 수 있음을 의미합니다.
++ 연산자가 오버로드 될 수없는 C #과 같은 다른 언어에서는 성능 차이가 없습니다. 루프 변수를 개선하기 위해 루프에서 사용되는 사전 및 사후 증분 연산자는 동일합니다.
수정 : C #에서 ++ 오버로드가 허용됩니다. 그러나 C ++과 비교할 때 c #에서는 사전 및 사후 버전을 독립적으로 오버로드 할 수 없습니다. 따라서 C #에서 ++를 호출 한 결과가 변수에 할당되지 않거나 복잡한 식의 일부로 사용되면 컴파일러는 ++의 사전 및 사후 버전을 동등한 성능을 가진 코드로 줄입니다.
C #에서는 for 루프에서 사용될 때 차이가 없습니다 .
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
와 같은 것을 출력
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
다른 사람들이 지적했듯이, 일반적으로 i ++ 및 ++ i에서 사용될 때 미묘하지만 중요한 차이점이 있습니다.
int i = 0;
Console.WriteLine(i++); // Prints 0
int j = 0;
Console.WriteLine(++j); // Prints 1
i ++는 i의 값을 읽은 다음 증가시킵니다.
++ i는 i의 값을 증가시킨 다음 읽습니다.
++i
와 i++
같은 순서로 같은 작업을 수행합니다 임시 복사본을 만듭니다 i
; 새로운 값을 생성하기 위해 온도 값을 증가시킵니다 (온도를 무시하지 않음) 새 값을 i
; 그것의 경우 현재 ++i
반환 된 결과는 새로운 값이다; 그것의 경우 i++
반환 된 결과 임시 복사본입니다. 자세한 답변은 여기에 있습니다 : stackoverflow.com/a/3346729/3330348
질문은 ~이야:
for 루프에서 ++ i와 i ++에 차이가 있습니까?
대답은 : 아니오 .
이것이 요구되지 않을 때 왜 각각의 모든 대답이 사전 및 사후 증분에 대한 자세한 설명으로 들어가야 하는가?
이 for- 루프 :
for (int i = 0; // Initialization
i < 5; // Condition
i++) // Increment
{
Output(i);
}
루프를 사용하지 않고이 코드로 변환합니다 :
int i = 0; // Initialization
loopStart:
if (i < 5) // Condition
{
Output(i);
i++ or ++i; // Increment
goto loopStart;
}
당신이 여기 에 i++
넣거나 ++i
증가 시키는 것이 중요 합니까? 증분 연산의 반환 값이 중요 하지 않으므로 아닙니다 . i
for 루프 본문 안에있는 코드 실행 후에 증가합니다.
루프의 차이점에 대해 묻는 것이기 때문에
for(int i=0; i<10; i++)
...;
이 경우 대부분의 언어에서 차이가 없습니다. 루프는 쓰기 i++
및에 관계없이 동일하게 작동합니다 ++i
. C ++에서는 사용자 정의 된 ++ 연산자 버전을 작성할 수 i
있으며 사용자 정의 유형 인 경우 (예를 들어 자체 클래스) 별도의 의미를 정의 할 수 있습니다 .
위의 사항이 중요하지 않은 이유는의 값을 사용하지 않기 때문입니다 i++
. 당신이 할 때 또 다른 것은
for(int i=0, a = 0; i<10; a = i++)
...;
지금, 거기에 있다 다른 사람들이 지적으로하기 때문에 차이는 i++
수단이 증가하지만, 이전 값으로 평가 하지만, ++i
수단의 증가가 이에 평가i
(따라서는 새 값으로 평가하는 것이다). 위의 경우 a
i의 이전 값이 할당되고 i가 증가합니다.
이 코드에서 알 수 있듯이 (주석에서 디스 어셈블 된 MSIL 참조) C # 3 컴파일러는 for 루프에서 i ++와 ++ i를 구분하지 않습니다. i ++ 또는 ++ i의 가치가 취해지고 있다면 분명히 차이가있을 것입니다 (이는 Visutal Studio 2008 / 릴리스 빌드에서 컴파일되었습니다).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PreOrPostIncrement
{
class Program
{
static int SomethingToIncrement;
static void Main(string[] args)
{
PreIncrement(1000);
PostIncrement(1000);
Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
}
static void PreIncrement(int count)
{
/*
.method private hidebysig static void PreIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PreIncrement
*/
for (int i = 0; i < count; ++i)
{
++SomethingToIncrement;
}
}
static void PostIncrement(int count)
{
/*
.method private hidebysig static void PostIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PostIncrement
*/
for (int i = 0; i < count; i++)
{
SomethingToIncrement++;
}
}
}
}
하나 (++ i)는 사전 증가분이고 하나 (i ++)는 사후 증가분입니다. 차이점은 식에서 어떤 값이 즉시 반환되는지에 있습니다.
// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1
편집 : Woops, 사물의 루프 측면을 완전히 무시했습니다. 'step'부분 (for (...; ...;)) 인 경우 for 루프에는 실제로 차이가 없지만 다른 경우에는 작동 할 수 있습니다.
루프에서 증분 후 값을 사용하지 않으면 차이가 없습니다.
for (int i = 0; i < 4; ++i){
cout<<i;
}
for (int i = 0; i < 4; i++){
cout<<i;
}
두 루프 모두 0123을 인쇄합니다.
그러나 루프에서 증가 / 감소 후 값을 다음과 같이 사용하면 차이가 발생합니다.
사전 증분 루프 :
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
출력 : 0011 2 3 3
포스트 증분 루프 :
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
출력 : 00 1012 3 2
출력을 비교하여 차이가 분명하기를 바랍니다. 여기서 주목할 것은 증가 / 감소는 항상 for 루프의 끝에서 수행되므로 결과를 설명 할 수 있습니다.
다음은 Java 샘플이며 바이트 코드, 사후 및 사전 증가는 바이트 코드에 차이가 없음을 나타냅니다.
public class PreOrPostIncrement {
static int somethingToIncrement = 0;
public static void main(String[] args) {
final int rounds = 1000;
postIncrement(rounds);
preIncrement(rounds);
}
private static void postIncrement(final int rounds) {
for (int i = 0; i < rounds; i++) {
somethingToIncrement++;
}
}
private static void preIncrement(final int rounds) {
for (int i = 0; i < rounds; ++i) {
++somethingToIncrement;
}
}
}
그리고 이제 바이트 코드 (javap -private -c PreOrPostIncrement)의 경우 :
public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;
static {};
Code:
0: iconst_0
1: putstatic #10; //Field somethingToIncrement:I
4: return
public PreOrPostIncrement();
Code:
0: aload_0
1: invokespecial #15; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: sipush 1000
3: istore_1
4: sipush 1000
7: invokestatic #21; //Method postIncrement:(I)V
10: sipush 1000
13: invokestatic #25; //Method preIncrement:(I)V
16: return
private static void postIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
private static void preIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
}
그렇습니다. 차이는 반환 값에 있습니다. "++ i"의 리턴 값은 i 를 증가 시킨 후의 값 입니다. "i ++"의 반환 값은 증분 전의 값입니다. 이것은 다음과 같은 코드를 의미합니다.
int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.
따라서 a는 2이고 b와 c는 각각 1입니다.
다음과 같이 코드를 다시 작성할 수 있습니다.
int a = 0;
// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.
// a++;
c = a; // setting first.
a = a + 1; // incrementing second.
루프와 성능 차이보다 ++ i와 i ++가 더 많습니다. ++ i는 l- 값을 반환하고 i ++는 r- 값을 반환합니다. 이를 바탕으로 할 수있는 일이 많지만 (++ i) 할 수는 없습니다 (i ++).
1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:
T& operator ++ ( )
{
// logical increment
return *this;
}
const T operator ++ ( int )
{
T temp( *this );
++*this;
return temp;
}
다음과 같은 i ++로 인해 자바 스크립트에서 사용하는 것이 좋습니다.
var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.
배열 (모두 생각)과 일부 다른 함수와 호출은 0을 시작점으로 사용하지만 ++ i를 사용할 때 루프가 배열과 작동하도록 i를 -1로 설정해야합니다 .
사용하는 경우 내가 ++ 다음 값이 증가 된 값을 사용합니다. 당신은 i ++ 가 인간을 계산하는 방식 이라고 말할 수 있습니다 .0으로 시작할 수 있습니다 .
FOR 루프가 하는 일을 이해하려면
위 이미지는 FOR 가 궁극적으로 완전히 동일한 어셈블리 코드 (최소한 gcc)를 갖기 때문에 WHILE 로 변환 될 수 있음을 보여줍니다 . 따라서 FOR 을 몇 개의 부분으로 나누고 그 기능을 이해합니다.
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
WHILE 버전 과 같습니다
i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
DoSomethingA();
DoSomethingB();
++i; //third argument (another statement) of for
}
FOR 를 간단한 버전의 WHILE 로 사용할 수 있습니다 .
FOR (int i) 의 첫 번째 인수 는 루프 외부에서 실행됩니다.
FOR (i ++ 또는 ++ i) 의 세 번째 인수 는 루프 의 마지막 줄 에서 실행됩니다.
TL : DR : 아무리 여부
i++
또는++i
, 우리는 그들이 독립 할 때, 그들은 자신에 대한 차이 만 +1하지 않습니다 것을 알고있다.학교에서는 대개 i ++ 방식을 가르치지 만 여러 가지 이유로 인해 ++ i 방식을 선호하는 사람들도 많습니다 .
참고 : 과거에 i ++는 그 자체로 1을 더할뿐만 아니라 레지스터에 원래 값을 유지하기 때문에 성능에 거의 영향을 미치지 않습니다. 그러나 지금은 컴파일러가 더하기 한 부분을 동일하게 만들면 아무런 차이가 없습니다.
루프에 차이가있을 수 있습니다. 이것은 사후 / 사전 증가의 실제 적용입니다.
int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);
i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();
첫 번째는 11로 계산되고 11 회 반복되지만 두 번째는 그렇지 않습니다.
대부분 이것은 간단한 while (x-> 0)에서 사용됩니다. --예를 들어 배열의 모든 요소를 반복하기 위해 반복합니다 (여기서는 for-constructs 제외).
예 사이의 차이가 ++i
와i++
for
. 예외적 인 경우에는 루프 루프 에 있습니다. 증가 / 감소 연산자 루프 변수가 사용될 때 블록에 대한 또는 루프 테스트에서 발현 또는 루프 변수 중 하나 . 아니요 그것은 단순한 구문이 아닙니다.
마찬가지로 i
코드 수단은 표현식을 평가 i
하고 운영자가 평가하지만 그냥 동작을 의미하는 것은 아니다;
++i
증분 값이 i
1 이상인 것을 의미합니다 i
.i++
평가 i
및 나중에 i
1 씩 증가 하는 것을 의미합니다 .따라서, 평가되는 것이 각각 다르기 때문에 각각의 두 표현에서 얻은 것이 다릅니다. 대한 같은 모든 --i
및i--
예를 들어;
let i = 0
i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2
비정상적인 사용 사례에서 다음 예제는 유용하거나 중요하지 않은 것처럼 들리지만 차이점이 있습니다.
for(i=0, j=i; i<10; j=++i){
console.log(j, i)
}
for(i=0, j=i; i<10; j=i++){
console.log(j, i)
}
내용은 i
'사용자 정의 형식의이야,이 연산자 (수 있지만이 안 ) 루프 인덱스의 맥락에서 의미 다른 sematics를 가지고 있고,이 (하지만 안) 루프의 동작 설명에 영향을 줄 수 있습니다.
또한 c++
사전 증분 양식 ( ++i
) 을 사용하는 것이 일반적으로 가장 안전합니다 ( 보다 쉽게 최적화 됨). (스콧 랭함 이이 끔찍한 일로 나를 이겼다 . 스캇을 저주하라)
나는 다른 언어에 대해 잘 모릅니다하지만 자바 ++ 난 A는 접두사 증가 하는 수단 : 증가 I를 1로하고있는 표현의 난의 새 값을 사용하여 내가 존재하고, 내가 ++ A는 후위 증가 다음을 의미한다 : 표현식에서 i 의 현재 값을 사용한 다음 1 씩 증가시킵니다. 예 :
public static void main(String [] args){
int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
} 출력은 다음과 같습니다.