가령
int a = 0;
do a++; while( a < 10 );
위 같은 코드는 실제로는 다음과 같이 번역됩니다.
어셈블리 코드로 적으면 낯설테니 그냥 pseudo code로.
a <- 0;
loop:
a <- a + 1
if( a < 10 )
goto loop;
만약
int a;
for( a = 0; a < 10; ++a );
와 같은 코드를 작성하면,
컴파일러가 최적화 하지 않는 경우 다음과 같은 코드로 번역됩니다.
a <- 0;
loop:
if ( a >= 10 )
goto next;
a <- a + 1
goto loop;
next:
차이를 아시겠어요?
do ~ while 은 3줄짜리 코드. ( 루프의 반복회수가 N 일 때 complexity 3N )
for는 4줄짜리가 됩니다. ( 루프의 반복회수가 N 일때 complexity 4N, 즉 25% 성능차이 )
하지만 컴파일러는 시작 초기화값 상수 0 이 10보다 작다는걸 알기 때문에
최적화를 걸면 for 문을 do ~ while 로 해석해서
세 줄짜리 코드를 만들어 줍니다.
do-while 을 안쓰다뇨.
루프에 들어갈때 조건을 판단하는거랑,
일단 실행하고 루프를 빠져나갈때 조건을 판단하는 구조는
명령어 1개 만큼의 최적화 영향을 받게 됩니다.
// str 이 char* 타입일때
while( *str++ ); 과
while( *str ) str++;
의 차이점도 아셔야 합니다.
전자는 null 문자를 만나고 나서 빠져나올때 하나 더 str 을 증가시키게 됩니다.
후자는 null 문자를 만난 위치에 포인터가 멈춰서게 되죠.
저걸 pseudo 코드로 나열하면, 다시 명령어 하나가 루프안에 더 있고 없고의 차이가 됩니다.
컴파일 되고 나면 *str++ 을 사용한쪽이 반복문 안에서의 명령어가 하나 적게 되기에
size_t strlen( const char* str )
{
char* ptr = (char*)str;
while( *ptr++ );
return ptr - str - 1;
}
이게
while( *ptr ) ptr++; 를 사용해서
return ptr - str; 하는 코드보다 효율적인 코드가 됩니다.
request 를 받아 위의 두 예도 pseudo code 를 작성합니다.
단, 이경우 if 문 형식과 어셈블리 코드가 조금 달라지니
최대한 x86 instruction 에 맞춰 비교구문을 test 라고 하겠습니다.
1. while( *ptr++ ); 의 경우
loop:
result_flag << test( *ptr, 0 );
ptr <- ptr + 1;
if( result_flag.contains( not_zero ) ) goto loop;
2. while( *ptr ) ptr++; 의 경우
loop:
result_flag << test( *ptr, 0 );
if( result_flag.contains( zero ) ) goto next;
ptr <- ptr + 1;
goto loop;
next:
위와같이 3줄 명령어 루프와 4줄 명령어 루프가 됩니다.
길어서일지안았읍니다
다 아는 분은 읽을 필요가 없습니다
str 예제도 의사코드 써주셨으면...
그러지요
일반적인for문도 결국엔 컴파일러 최적화거치면 do~while이랑 같은성능이라는거죠 그럼? 아닌경우엔 do~while이 더 낫지만? ++의경우는 걍눈으로보기에도 더 깨끗해보여서 그렇게 쓰도록 해오고있어서 이런장점이있었는지까진 생각하진못했지만.,,,
만약 초기값이 상수가 아닐때는 do-while 로 최적화 되지 않습니다.
진입시 확인을 하게 되죠. 그러면 당연히 기본골격 4줄 코드가 되고 느려지겠죠?