매개변수 전달 기법은 함수가 호출될 때, 함수에 데이터를 전달하는 방법을 말한다.

 

매개변수를 전달하는 방식은 여러 가지가 있고, 각 기법은 함수 호출 시의 동작 방식과 메모리 사용에 따라 다르다.

  • 값에 의한 전달
  • 주소에 의한 전달
  • 참조에 의한 전달

 

📌 값에 의한 전달( Call by Value )

값에 의한 전달은 가장 기본적인 매개변수 전달 기법이다.
함수 호출 시 매개변수에 전달된 값이 복사되어 함수의 지역 변수에 저장( Stack에서 관리 )된다.
  • 함수 호출 시, 매개변수의 값이 복사되어 함수에 전달
  • 함수 내부에서 해당 값을 수정해도 호출한 함수의 값은 변경되지 않는다.

예시

#include <stdio.h>

void Test(int x) {
    x = 20;  // 함수 내부에서만 x의 값이 변경됨
}

int main() {
    int a = 10;
    Test(a);  // a의 값을 Test에 전달, 값이 복사됨
    printf("%d\n", a);  // 출력: 10
    return 0;
}

 

📌 주소에 의한 전달( Call by Reference )

주소에 의한 전달은 함수 호출 시 매개변수의 주소를 전달하는 방식이다.
  • 함수 호출 시, 매개변수의 주소가 전달된다.
  • 함수 내부에서 해당 주소를 통해 원본 변수에 접근하여 값을 변경할 수 있다.

예시

#include <stdio.h>

void Test(int *x) {
    *x = 20;  // 포인터를 통해 원본 변수의 값을 수정
}

int main() {
    int a = 10;
    Test(&a);  // a의 주소를 전달
    printf("%d\n", a);  // 출력: 20
    return 0;
}

 

📌 참조에 의한 전달( Call by reference )

참조에 의한 전달은 주소에 의한 전달과 비슷한 방식으로, 함수 호출 시 매개변수의 참조를 전달한다.
  • 함수 호출 시 매개변수의 참조가 전달된다.
  • 함수 내부에서 해당 참조를 통해 원본 객체나 데이터를 수정할 수 있다.
#include <iostream>
using namespace std;

void Test(int &x) {
    x = 20;  // 참조를 통해 원본 변수 값 수정
}

int main() {
    int a = 10;
    Test(a);  // 참조를 전달
    cout << a << endl;  // 출력: 20
    return 0;
}

 


 

앞선 글에서 쓰레드마다 Stack의 크기는 1MB로 제한되기 때문에 매개변수로 데이터를 전달할 때

값 복사가 이뤄지지 않도록 해야한다.

매개변수와 자동변수(=지역변수)는 모두 스택( Stack )영역에서 관리한다.

프로세스는 최소 한개 이상의 쓰레드를 가지고 있다.

 

쓰레드가 사용할 수 있는 스택의 크기는 1MB 로 한정된다.

#include<stdio.h>
#include<string.h>

int main(void)
{
    char szBuffer[1024];
    strcpy_s(szBuffer, sizeof(szBuffer), "Hello world");
    printf("%s\n", szBuffer);
    
    return 0;
}

 

위와 같이 코드를 작성하고 돌리면 Hello world가 출력된다.

 

#include<stdio.h>
#include<string.h>

int main(void)
{
    char szBuffer[1024 * 1024];
    strcpy_s(szBuffer, sizeof(szBuffer), "Hello world");
    printf("%s\n", szBuffer);
    
    return 0;
}

 

위와 같이 코드를 작성하고 돌리면 Hellow world가 출력되지 않는다.

위 코드 2개의 다른점은 char szBuffer 배열의 크기인데, 아래는 1024 * 1024로 1MB로 스택의 크기를 넘어가버렸기 때문에 

Stack overflow 런타임 에러가 발생해 출력되지 않는 것이다.

 

Stack overflow 발생

 

Stack의 크기는 프로젝트 속성 - 링커 - 시스템에서 스택 예약크기를 수정해서 변경할 수 있다.

보통은 1MB 이면 충분하기 때문에 수정하지 않고 사용한다.

 

이처럼 Stack의 크기는 한정적이기 때문에 유의하면서 사용해야 한다. 

  • 용량이 큰 구조체 자체를 매개변수로 전달할때 값 복사가 일어나지 않게 해야함
  • 함수가 다른 함수를 호출할때, 호출이 얼마나 이어지는지도 생각해야함

 

📌 호출자( Caller )

함수를 호출하는 대상을 말한다.

📌 피호출자( Callee )

함수에게 호출당하는 대상을 말한다.

 

모든 호출자와 피호출자는 호출자이면서 피호출자일 수 있다.

또한 호출자는 호출자와 피호출자로 묶인 관계까지만 생각하고, 피호출자가 호출자인지는 생각하지 않는다.

 

호출자는 피호출자를 호출하면, 결과값을 얻을 수 있다.

결과값은 피호출자 함수의 연산 결과이거나 피호출자 함수의 연산이 잘 수행되었는지 확인하는 결과일 수 있다.

 

반면, void는 반환받는 결과값이 없는 반환형이다.

호출자가 void를 반환형으로 하는 피호출자를 호출하는 것은 피호출자에서 제어의 흐름이 가고 코드 연산이 이루어 진 후

흐름이 되돌아오는 것에만 관심이 있다고 생각할 수 있다. 즉, 피호출자 함수가 잘 작동 했는지 못했는지, 아니면 연산 결과를 회수 받기 위한 의도가 전혀 없다는 것을 말한다. 호출에 의해 흐름이 넘어갔다 돌아왔다라는 것만 생각하겠다는 의미

 

호출, 피호출 관계에 있어서 한번 더 생각해야하는 점은 둘의 관계가 모듈이 분리가 되어있는지 생각해봐야하고,

경우에 따라서 호출, 피호출이 쓰레드가 바뀌어 버릴수도 있는지도 생각을 해야한다. 

 

  • 최종 바이너리는 .dll 파일이다.
  • .c, .h, lib, .dll 네 가지 파일로 구성된다.
    • .h는 컴파일 타임에 사용된다.
    • .lib는 링크 타임에 사용된다.
    • .dll은 런 타임에 사용된다.
      • 런타임 라이브러리를 로딩하는 방식은 2가지로 나뉜다.
        • 묵시적 방법
        • 명시적 방법

📌 Visual Studio에서 동적 라이브러리 개발

#include <stdio.h>

int add_in_dll(int a, int b)
{
	puts("add_in_dll v1.0");
	return a + b;
}

 

 

 

위 그림처럼 동적 라이브러리를 만들기 위해 구성 형식을 변경한다.

 

동적 라이브러리를 링킹 하는 주체는 운영체제인데, 프로세스를 로딩할 때 한다.

따라서 운영체제에게 알려주는 코드가 추가로 들어가야한다.

 

__declspec(dllexport) int add_in_dll(int a, int b);

 

 

위 명령어를 통해 add_in_dll을 외부에 공개함으로써 사용할 수 있게 한다. 

 

사용해보기 위해 프로젝트 하나를 더 만들자

 

 

 

정적 라이브러리와 마찬가지로 링크 에러가 난다.

 

동적 라이브러리를 사용하려면 다음과 같이 코드를 입력한다.

__declspec(dllimport) int add_in_dll(int a, int b);

 

 

이렇게 입력하고 빌드하면 링크에러가 또 나는데, 경로를 지정안해줘서 그렇다.

 

 

위 그림처럼 pragma comment를 사용해 경로를 지정해주면 링크에러가 잡히고 동적 라이브러리를 사용할 수 있다.

정적 라이브러리와 동적 라이브러리는 프로그램 개발에서
코드의 재사용성과 모듈화를 위해 사용되는 함수를 모아 놓은 실행 파일을 말한다.

 

📌 정적 라이브러리( Static Library )

정적 라이브러리는 실행 파일과 Link타임에 결합되어 한 실행 파일로 합성되는 것을 말한다.

 

특징

  • 파일 확장자
    • .lib
  • 컴파일 및 링크 과정
    • 라이브러리의 소스 코드를 컴파일하여 개별적인 오브젝트 파일( .o 또는 .obj )을 생성한다.
    • 이 오브젝트 파일들을 하나의 정적 라이브러리 파일( .a 또는 .lib )로 묶는다.
    • 프로그램을 빌드할 때 정적 라이브러리를 포함하여 최종 실행 파일을 생성한다.
  • 배포 방식
    • 실행 파일에 라이브러리 코드가 포함되므로, 라이브러리 파일을 별도로 배포할 필요가 없다.
  • 속도
    • 실행 속도가 빠르다. ( 라이브러리가 이미 실행 파일에 포함되어 있기 때문 )
  • 단점
    • 실행 파일의 크기가 커진다.
    • 라이브러리가 변경되면, 모든 프로그램을 다시 컴파일 해야 한다.

 

📌 동적 라이브러리( Dynamic Library )

동적(= 런타임) 라이브러리는 실행 파일과 링크타임에 결합되지 않고 독립적인 실행파일 형태로 생성되며
실행 파일이 실행 될 때 '동적으로' 결합되는 것을 말한다.

 

특징

  • 파일 확장자
    • .dll
  • 컴파일 및 링크 과정
    • 라이브러리의 소스 코드를 컴파일하여 개별 오브젝트 파일( .o 또는 .obj )을 생성한다.
    • 동적 라이브러리( .so, .dll, .dyblib )를 생성한다.
    • 프로그램을 컴파일할 때 라이브러리를 참조하지만, 실행 시점에 라이브러리를 로드한다.
  • 배포 방식
    • 실행 파일에는 라이브러리 코드가 포함되지 않으며, 별도의 동적 라이브러리 파일이 필요하다.
  • 메모리 사용 최적화
    • 여러 프로그램이 하나의 동적 라이브러리를 공유하기 때문에 메모리 사용이 정적 라이브러리보다 효율적이다.
  • 업데이트 용이성
    • 라이브러리를 수정해도 프로그램을 다시 컴파일할 필요 없이 새 라이브러리만 배포하면 된다.
  • 단점
    • 실행 시 라이브러리를 로드해야 하므로 성능이 정적 라이브러리보다 약간 낮을 수 있다.
    • 라이브러리가 없거나 버전이 맞지 않으면 실행 오류가 발생할 수 있다.
  • 1 비트란 '전기 스위치 1개'를 의미한다.
  • 전기가 흐르는 On 상태는 1이다.
  • 전기가 흐르지 않는 Off 상태는 0이다.

📌 2진수, 16진수 진법 변환

2진수(4비트) 16진수
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 B
1100 C
1101 D
1110 E
1111 F
  • 4비트16진수 한 자리 숫자다.
  • 16진수는 0 ~ F( 십진수 15 )까지 한 자리에 쓴다.

📌 16진수 표기가 사용되는 예

  • 색상 표현
  • 컴퓨터 하드웨어 주소 표현
  • 메모리 값 표현

메모리 주소

 

CSS에서 16진수로 색상을 표기한다.

  • 8개 비트를 하나로 묶어 1 바이트( byte )라고 한다.
  • 1 바이트는 영문자 한 글자가 저장될 수 있는 메모리 크기고 관리의 최소단위다.
    • 한글 한 글자를 저장하려면 2바이트가 필요하다.
  • 4비트는 16가지, 8비트는 256가지, 16비트는 65536가지( 64KB )다.
  • 2의 32제곱은 42,9496,7296 ( 약 42.9억 )이다. 42,9496,7296 바이트는 4GB이다.
  • 2의 32제곱은 32 bit를 의미한다. 즉, 32비트 구조상 관리할 수 있는 한계 용량은 4GB다.

📌 컴퓨터 메모리 용량을 말하는 단위

단위 크기 특징
1 Bit( 비트 ) 전기 스위치 1개 용량이 아닌 표현의 최소 수준
1 Byte( 바이트 ) 8비트 한 묶음 영문자 한 글자를 저장할 수 있는 기억 공간의 최소단위다.
( 컴퓨터는 기억공간을 관리할 때 1바이트 단위로 관리한다 )
1 KB( 킬로 바이트 ) 1024 바이트 보통 JPEG 사진 파일 하나가 몇 백 KB 정도 된다
1 MB( 메가 바이트 ) 1024 킬로 바이트 MP3 파일 하나가 대략 4 ~ 5 MB 정도 크기
1 GB( 기가 바이트 ) 1024 메가 바이트 영화(.avi나 .mp4) 파일 하나가 대략 2 ~ 6 GB 정도 크기
1 TB( 테라 바이트 ) 1024 기가 바이트 하드 디스크 1개 용량이 보통 1 ~ 2 TB 정도 크기
1 PB( 페타 바이트 ) 1042 테라 바이트 2016년 7월 기준 네이버 IDC 센터 규모는 약 900 PB 정도
1 EB( 엑사 바이트 ) 1024 페타 바이트 64비트를 용량으로 계산하면 16 EB가 된다
1 ZB( 제타 바이트 ) 1024 엑사 바이트 2017년 기준 전 세계 데이터 센터 트래픽이 약 7.7 제타 바이트다.
1 YB( 요타 바이트 ) 1024 제타 바이트  

 

📌 컴퓨터가 글자를 다루는 방법

  • ASCII( American Standard Code for Information Interchange )는 미국에서 사용하는 표준 코드체계다.
    • 십진수 64 = 'A' = 0x41
  • 숫자와 글자를 구별하지 않고 정보를 말 할때는 바이너리( Binary )라고 한다.

 

📌 컴퓨터가 사진을 다루는 방법

  • 모니터 화면 상 '점' 하나를 화소( Pixel )이라 한다.
  • 여러 점들을 모아 사진을 만들 수 있다.
  • 화소 하나를 표현하는데 8비트, 16비트, 24비트, 32비트 정보가 필요할 수 있다.
  • 빛의 3원색은 Red, Green, Blue다. 이점에 착안해 RGB 컬러가 등장한다.
  • 화소가 작을 수록 사진이 매끄럽다 ( 고해상도 )

+ Recent posts