1. 시작하기전에 생각해볼 것 3가지

어떠한 값이 나올까? 에 대해 한번 곰곰히 생각해보자

 

첫 번째 케이스

두 번째 케이스

세 번째 케이스

3가지 경우에는 어떤 값이 출력이 될까?

 

1. Call by Value

 

 

첫 번째 경우에 a = 1 b = 2가 출력이 된다.

 

 

1. main 함수와 swap 함수

main 함수에서 a = 1, b = 2라는 값을 복사하여서 swap 이라는 함수로 전달한 것이기 때문에,

swap 안에서의 a 와 b는 main의 a 와 b 와는 엄연히 다른 메모리 영역을 가지는 변수  이다.

다시 말해 swap 안의 a와 b는 main의 a와 b 값을 복사해 그대로 전달했을 뿐 다른 함수이고, 두 함수는 아무런 관련이 없다.

 

 

2. 함수 종료 시 a와 b도 소멸

swap 함수가 종료됨과 동시에 swap 함수의 a,b는 사라진다. 정확히 말하면 c언어에서 할당받은 메모리의 변수의 값이 지워졌다기보다는 더 이상 보호를 받지 못하고, 다른 프로그램에 의해 다른 값으로 덮어쓰여지거나 임의의 값이 쓰여진다. 얼마나 시간이 지나야 다른 프로그램에 의해 값이 덮어쓰여질지는 모르지만 프로그래머가 제어할 수 없는 값이니 사라진다는 표현을 사용한다. 

 

 

그러면 어떻게 call by value에서 값을 전달할 수 있을 까? 

 

이러한 경우에 return을 사용하여 main 함수의 변수에 대입을 하면 가능하다.

하지만 c언어의 경우 하나의 변수만 return 할 수 있으므로, 여러 개의 변수를 반환하고 싶으면 구조체나 배열을 통해 반환을 해야한다.


2. Call by Reference

두 번째 케이스는 a = 2, b = 1이 출력된다.

 

1. main 함수와 swap 함수

 

main 함수에서 a = 1, b = 2라는 값의 주소를 넘겨주었기 때문에

swap 안에서의 a 와 b는 main의 a 와 b 와는 같은 메모리 영역을 가지는 변수  이다.

 

 

따라서 swap 안에서 포인터를 통해 특정 메모리의 값을 바꾸었으므로, 함수가 종료되어도

main 함수에서 a와 b 값이 바뀐 것을 확인할 수있다.


 

3. 함수와 메모리 

 

세 번째의 정답은 알 수 없다 이다.

 

왜냐하면 returnaddress에서 선언한 변수 b는 b의 주솟값을 반환하고, 종료한다.

이때 변수 b는 returnaddress에서 선언된 지역변수 이므로, 함수가 종료됨에 따라 소멸한다.

첫 번째 케이스에서 봤던 것처럼, 정확히는 보호를 받지 못하고, 일정 시간이 지나면 다른 프로그램에 의해서 

덮어쓰여지거나 임의의 값으로 덮어쓰여진다.

 

따라서 덮어쓰여지기전에 값이 출력이 된다면 예상한 값이 나올 것이고, 그렇지 않다면 다른 값이 나올 것이다.

 

출력값은 다음과 같이 나온다.

 

 

 


4. 정리

call by value는 값을 복사해온 것이므로, 이것에 의해 생성된 변수는 실제(원본이 되는) 변수와 다른 메모리 영역을 가지는 변수로 실제 변수에 영향을 미치지 못한다.

 

call by reference는 주소값을 복사해온 것이므로, 실제(원본이 되는) 변수와 같은 메모리 영역을 가지는 변수로 pointer를 이용하여 해당하는 주소값의 value를바꿀 수 있다.

 

local 변수는 함수가 끝나면 소멸하고, 여기서 소멸한다는 뜻은 즉시 사라진다는 뜻이 아니라 보호받지 못하는 변수를 의미한다.

 

'Program Language > C' 카테고리의 다른 글

[C] Big Endian vs Little Endian  (0) 2023.11.06

1. Endian

Endian은 걸리버 여행기의 소인국 이야기에서 달걀을 깰 때, 뭉툭한 끝(big-end)을 먼저 깨는 사람들(빅 엔디언)과 뾰족한 끝(little-end)을 먼저 깨는 사람들(리틀 엔디언) 에서 유래된 것으로, 컴퓨터 아키텍에서 메모리에 자료가 저장하고 표현할  바이트 단위로 저장되는 방식을 의미한다.

 

부호가 없는 unsigned int를 가지고 이야기를 해보고자 한다.

 

C언어에서 unsigned int 형의 범위는 0 ~ 4,294,967,295 이지만, 컴퓨터 아키텍쳐에서 메모리의 한 Byte의 크기는 256 이므로 unsigned int는 너무 커서 1byte에 모두 담을 수 없고,  4 byte에 나누어 담아야한다. 메모리에 4byte에 해당하는 값을 저장하게 된다.

 

 

- 낮은 byte를 높은 주소에 저장하는 가?

- 높은 byte를 높은 주소에 저장하는 가?

 

 

낮은 byte를 높은 주소에 저장한다면 Big Endian, 높은 byte를 높은 주소에 저장한다면 Little Endian이라고 한다.

이해가 잘 가지 않을 수 있으니 아래에서 좀 더 자세히 다루어보자!

 

2. Big Endian

Big Endian은 낮은 자리의 Byte가 높장 낮은 자리의 주소에 저장되는 방식이다.

 

 

IBM 또는 Motorola 의 많은 시스템들이 big Endian 방식을 사용하고 있음.

 

 

3. Little Endian

little Endian은 낮은 자리의 byte가 낮은 자리의 주소에 저장되는 방식이다.

 

intel 계열의 cpu와 AMD의 processor는 Little Endian 방식을 사용하고 있음.

 

 

4. Little Endian 실습

 

# define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main() {
	unsigned int number;
	unsigned char arr[4];

	scanf("%u", (int*)arr);

	for (int i = 0; i < 4; i++) {
		printf("%hhu", &arr[i]);
	}

	return 0;
}

 

위의 예시 코드를 가지고 한 줄씩 디버깅을 하면서 살펴보자

insigned int 변수를 선언했고, unsigned char 배열을 선언했다.

그리고 scanf 함수를 이용해서 305419896을  unsigned char 배열에 int*형의 값을 넣어주었다.

 

 

무슨 일이 일어날까??

조사식을 보면 다음과 같다.

 

 

 

 

 

위의 조사식에서

앞에있는 값은 10진수, 뒤에 있는 값은 아스키 코드를 나타낸다.

따라서 10진수를 16진수로 바꾸어보면

 

120 -> 0x78

86   -> 0x56

52   -> 0x34

12   -> 0x12

 

이처럼 높은 바이트의 값이 높은 주소에 저장되어 있다는 것을 알 수있다.

 

 

현재 우리가 사용하고 있는 대부분의 cpu (intel 또는 amd) 는 Little Endian 방식을 사용하고, 다음과 같이 실습해 볼 수있을 것이다. 다만 Mac의 경우는 조금 다를 수 있다.

'Program Language > C' 카테고리의 다른 글

[C] Call by Reference VS Call by Value  (0) 2023.11.06

+ Recent posts