다루는 내용
- 증감 연산자와 산술 연산자와의 비교
- 어셈블리 코드 확인하기(디스어셈블리)
증감연산자는 단항 연산자로 ++, -- 연산자가 있다.
증감연산자는 기본적으로 자기 자신의 값을 1증가(++), 1감소(--)시키는 연산 행위를 한다.
하지만 연산 결과는 전위에 연산자가 왔을 때는 변경된 자기 자신의 값이고 후위에 왔을 때는 변경되기 전 값이다.
이는 증감연산의 결과를 사용을 하려했을 때는 전위 연산 표현인지 후위 연산 표현인지에 따라 영향을 미치게 된다.
Look & Feel & Think
전위에 연산자가 왔을 때(++i)
C언어 | 어셈블리 | 설명 |
int i = 0; | mov dword ptr [i],0 | 변수 i에 0으로 초기화 |
++i; | mov eax,dword ptr [i] | eax레지스터에 변수 i를 대입 |
add eax,1 | eax레스트터에 1을 더한다. | |
mov dword ptr [i],eax | 변수 i에 eax레지스터 대입 |
후위에 연산자가 왔을 때(i++)
C언어 | 어셈블리 | 설명 |
int i = 0; | mov dword ptr [i],0 | 변수 i에 0으로 초기화 |
mov ecx,dword ptr [i] | eax레지스터에 변수 i를 대입 | |
i++; | add ecx,1 | eax레스트터에 1을 더한다. |
mov dword ptr [i],ecx | 변수 i에 eax레지스터 대입 |
자기 자신에 1을 더하는 코드(i = i +1)
C언어 | 어셈블리 | 설명 |
int i = 0; | mov dword ptr [i],0 | 변수 i에 0으로 초기화 |
mov ecx,dword ptr [i] | eax레지스터에 변수 i를 대입 | |
i = i+1; | add ecx,1 | eax레스트터에 1을 더한다. |
mov dword ptr [i],ecx | 변수 i에 eax레지스터 대입 |
위의 세 개의 표를 보면 C언어 코드는 다르지만 어셈블리 코드는 완벽히 일치함을 알 수 있다.
즉, 증감연산자의 연산행위는 전위에 오거나 후위에 오거나 상관없이 동일함을 알 수 있다.
Look & Feel & Think
전위에 증감연산자가 오고 연산 결과를 다른 변수에 대입(re = ++i)
C언어 | 어셈블리 | 설명 |
int i = 0; | mov dword ptr [i],0 | 변수 i에 0으로 초기화 |
int re = 0; | mov dword ptr [re],0 | 변수 re에 0으로 초기화 |
re = ++i; | mov eax,dword ptr [i] | eax레지스터에 변수 i를 대입 |
add eax,1 | eax레스트터에 1을 더한다. | |
mov dword ptr [i],eax | 변수 i에 eax레지스터 대입 | |
mov ecx,dword ptr [i] | ecx레지스터에 변수 i대입 | |
mov dword ptr [re],ecx | re변수에 ecx대입 |
자신을 1 더한 후에 변경된 값을 다른 변수에 대입하는 코드 (i = i+1; re = i;)
C언어 | 어셈블리 | 설명 |
int i = 0; | mov dword ptr [i],0 | 변수 i에 0으로 초기화 |
int re = 0; | mov dword ptr [re],0 | 변수 re에 0으로 초기화 |
i = i +1; | mov eax,dword ptr [i] | eax레지스터에 변수 i를 대입 |
add eax,1 | eax레스트터에 1을 더한다. | |
mov dword ptr [i],eax | 변수 i에 eax레지스터 대입 | |
re = i; | mov eax,dword ptr [i] | eax레지스터에 변수 i를 대입 |
mov dword ptr [re],eax | re변수에 eax대입 |
위의 두 표를 보면 두 개의 어셈블리가 일치함을 알 수 있다.(사용하는 범용 레지스터가 다르지만 연산의 내용은 동일)
후위에 증감연산자가 오고 연산 결과를 다른 변수에 대입(re = i++)
C언어 | 어셈블리 | 설명 |
int i = 0; | mov dword ptr [i],0 | 변수 i에 0으로 초기화 |
int re = 0; | mov dword ptr [re],0 | 변수 re에 0으로 초기화 |
re = i++; | mov eax,dword ptr [i] | eax레지스터에 변수 i를 대입 |
mov dword ptr [re],eax | 변수 re에 eax레지스터 대입 | |
mov ecx,dword ptr [i] | ecx레지스터에 변수 i를 대입 | |
add ecx,1 | ecx레스트터에 1을 더한다. | |
mov dword ptr [i],ecx | 변수 i에 ecx레지스터 대입 |
자신을 다른 변수에 대입한 후 자신을 1 더하는 코드 (re = i; i = i+1;)
위의 두 표를 보면 두 개의 어셈블리가 일치함을 알 수 있다.(사용하는 범용 레지스터가 다르지만 연산의 내용은 동일)
이를 통해 증감연산자의 경우 연산의 결과는 연산자의 위치에 따라 다름을 알 수 있다.
본인은 증감연산자의 결과를 사용하는 구문은 사용하지 않는다.
이는 코드를 다시 볼 때 생각을 좀 더 해야 한다는 것이다. 즉, 가독성을 떨어트리는 요소가 된다.
하지만 다른 연산자와 같이 사용을 하지 않으면 연산 결과를 사용하지 않기 때문에 즐겨 사용한다.
증감 연산자는 연산자의 위치에 상관없이 연산 행위는 동일하나 연산 결과는 다르다.
증감연산자는 다른 연산과 같이 사용하지 말자.
어셈블리 코드 확인하기
먼저 고급 언어 코드와 어셈블리 코드, 기계어의 차이에 대해 얘기를 하자.
고급 언어 코드는 자연어 형식에 맞게 만든 언어를 고급 언어라 하며 해당 고급 언어 문법에 맞게 작성된 코드이다.
컴파일러는 이를 기계어로 번역을 하게 된다.
기계어는 실제 컴퓨터에서 수행하는 코드로 0과 1의 집합으로 되어 있는 코드를 얘기를 한다.
우리가 보통 어셈블리를 기계어라 얘기를 하지만 어셈블리 코드는 기계 명령 대신 니모닉을 이용하여 기계어와 1기계어와 1:1 매핑되어 있는 코드를 말한다. 즉, 0과 1로 기계어 코드를 작성하는 것과 1:1 매핑시켜 작성하기 쉽게 만든 언어를 어셈블리어라 한다.
그리고 어셈블리어로 만든 코드는 어셈블러에 의해 기계어로 바뀌는데 이러한 과정을 어셈블리라 하고 역으로 기계어 코드를 어셈블리 코드로 변환하는 것을 디스 어셈블리라 한다.
여기서는 Visual Studio 2008에서 디스 어셈블리를 이용하여 어셈블리 코드를 확인하는 방법을 얘기할 것이다.
1. 먼저 소스 코드에 BreakPoint를 설정한다.
단순히 라인위에 마우스 왼쪽 버튼을 클릭하면 설정 다시 클릭하면 해제된다.
설정 후에 F5로 디버깅 시작을 누르면 BreakPoint 앞까지 실행되서 Break포인터에서 멈춘다.
2. BreakPoint에서 멈추면 디버그 메뉴→창→디스어셈블리(단축키:Ctrl+Alt+D)를 선택하자.
3. 다음과 같은 디스어셈블리 창이 뜬다.
기계어는 문법이 단순해서 무슨 내용인지 이해하기 어렵지 않다. 다만 단순한 문법을 이용해서 커다란 프로그램을 작성하는 것이 힘들 뿐이다. 용기를 갖고 손가락에 힘을 주고 키보드를 누르고 약간의 Thinking을 하면 뭔가 느낄 수 있을 것이다.
'언어 자료구조 알고리즘 > C 언어 문법' 카테고리의 다른 글
17.기본 입출력 개요 (0) | 2009.08.19 |
---|---|
16. 지시/주소/인덱스/간접연산자 (0) | 2009.08.19 |
15. 비트/ 쉬프트 연산자 (0) | 2009.08.19 |
14. 비교/논리 연산자 (0) | 2009.08.19 |
13. 대입 연산자 (0) | 2009.08.19 |
11. 산술 연산자 (0) | 2009.08.19 |
10. 연산자 (0) | 2009.08.19 |
9. 변수의 종류 (0) | 2009.08.19 |
8. 변수의 선언과 초기화 (5) | 2009.08.19 |
7.사용자 정의 형식 - 구조체, 공용체, 열거형 (0) | 2009.08.19 |