Study/TIL(Today I Learned)

24.02.07 C & C++

에린_1 2024. 2. 7. 23:21
728x90

C & C++

선언(declaration)과 정의(definition)

  • 프로그래밍에서 선언(declaration)과 정의(definition)는 명백히 다른 역할을 하지만 혼동하여 사용하기 쉽다.
  • 선언과 정의의 가장 큰 차이는 ‘메모리를 할당하는가’ 이다.
  • 메모리를 할당하지 않고, 대상의 이름만 알려준다면 선언이고 대상의 메모리가 할당된다면 그것은 정의다.

선언

  • 컴파일러가 참조할 식별자(identifier)와 이름을 알립니다.
    • 식별자란 변수의 타입과 함수의 인수목록을 뜻하며 이름은 변수, 함수, 클래스의 이름, 네임 스페이스를 뜻합니다.

정의

  • 정의는 식별자와 이름으로부터 코드를 생성하여, 함수가 호출되거나 변수를 사용할 때 생성된 코드를 참조한다.
  • 정의는 고유 사양으로 프로그램에는 정의가 하나만 있어야 한다. 같은 식별자와 이름의 정의가 두 개 이상이라면 컴파일 에러가 발생한다. 반면, 선언만 하고 정의를 하지 않은 경우에는 링커 단계에서 참조할 코드가 없기 때문에 링커에러가 발생하는데 예외 사항 아래의 경우 정의가 필요 없다.
    • 함수가 선어만 있고 정의가 없지만 함수를 호출하거나 함수의 주소를 참조하는 일이 없음
    • 정의를 알 필요가 없는 방식으로만 사용됨(전방 선언)

전방 선언(forward declaration)

  • 함수나, 구조체, 열거자, 공용자, 외부(extern) 변수 등을 실제 구현(implementation) 시점보다 앞서서 선언(declare)만 하는 것을 말한다.
  • 물론, 구현부와 선언부의 서명(signature)은 일치해야 한다.
  • 서로를 호출하는 함수, 외부(extern) 변수, plmple기법 등에서 사용된다.
  • 헤더와 소스 파일로 구현부, 선언부를 분리하는 행위는 기본적으로 모두 전방 선언에 속한다.

static, extern 변수

  • static의 역할 : 현재 파일 내에서의 지역변수로 바뀐다. 즉, 현재 파일 내에서만 사용 가능한 변수가 된다.
  • extern의 역할 : 다른 파일에서 이미 이름이 같은 전역변수가 선언이 되었다는 의미. 즉, 다른 파일간의 변수를 공유하고 있다는 뜻이다.
  • static이 붙어있는 변수
    • 현재 파일 내에서만 존재하는 파일의 지역변수 취급을 받기 때문에 이름이 같더라도 서로 다른 파일에서 각각 다른 변수로 취급이 된다.
    • 따라서 static 변수를 통해 혹시 모를 전역변수의 이름이 같게 되는 문제를 조금이나마 완화할 수 있다.
    • 초기화를 생략하면 0으로 자동 초기화된다.
    • 외부 파일에서 접근이 불가능하다.
  • extern이 붙어있는 변수
    • 정말 global 변수라는 뜻으로 사용되며 다른 파일에 같은 이름의 전역변수가 존재한다는 것이기 때문에 이 정보를 컴파일러에게 전달하고 main.o와 header.o를 링킹 해준다.
    • 진정한 global 변수라고 볼 수 있다.
    • extern 키워드는 전역변수가 외부에 있다는 것을 표시만 할 뿐이고 선언을 하지는 않는다. 따라서 어디엔가 정의되어 있지 않으면 링크에러가 발생하게 된다.
    • extern은 다른 파일의 함수나 변수를 가져오는것 이외에도 현재 파일내에서도 작동이 가능하다.

enum

enum

  • 열거형은 정수형 상수에 이름을 붙여서 코드를 이해하기 쉽게 해준다.
enum 열거형이름 {
    값1 = 초깃값,
    값2,
    값3
};

전처리 명령

  • #include
    • #include <파일명> : C언어 기본 라이브러리를 포함할 때 사용
    • #include “파일명” : 우리가 임의로 만든 파일을 포함할 때 사
    • 파일을 포함한다.
  • #define
    • 매크로명을 정의해서 복잡한 상수나 문장을 의미있는 단어로 사용할 수 있도록 한다.
    • #define 매그로명 확장문자열
  • #if, else, elif, ifdef, ifndef, endif
    • 조건부 컴파일은 프로그램 코드를 조건에 따라 선택적으로 컴파일 할 수 있도록 전처리 단계에서 걸러준다.
    • 조건식에 괄호가 필요 없으며 반드시 #endif로 끝을 표시해 준다.
    • 헤더 파일이 겹치는 것을 막기 위한 일종의 매크로이다.
  • #error
    • 소스 라인에 직접 에러 메세지를 출력한다. 전처리기가 #error문을 만나면 그 즉시 컴파일을 중단하고 다음과 같은 에러 메시지를 출력한다.
  • #pragma
    • 컴파일 옵션의 지정. 컴파일러 작성자에 의해서 정의된 다양한 명령을 컴파일러에게 제공하기 위해 사용되는 지시어이다. 컴파일러의 여러 가지 옵션을 명령행에서가 아닌 코드에서 직접 설정한다. #pragma는 함수의 바로 앞에 오며 그 함수에만 영향을 준다.

반복자(iterator)

  • 어떤 컨테이너(자료구조)에 접근하든 동일한 방법으로 접근하기 위해서 제공되는 객체.
  • 자료구조마다 서로 다른 방법으로 내부의 요소들에 접근을 하는데 반복자를 사용하게 되면 컨테이너의 내부 구조를 몰라도 쉽게 컨테이너를 순회하는게 가능해지며, 서로 다른 컨테이너에 통일된 인터페이스로 접근이 가능하다.

비트 연산자

  • 비트 연산자는 비트(bit) 단위로 논리 연산을 할 때 사용하는 연산자이다.
  • 또한, 비트 단위로 전체 비트를 왼쪽이나 오른쪽으로 이동시킬 때도 사용한다.

비트 연산자 설명

& 대응되는 비트가 모두 1이면 1을 반환함. (비트 AND 연산)
| 대응되는 비트 중에서 하나라도 1이면 1을 반환함. (비트 OR 연산)
^ 대응되는 비트가 서로 다르면 1을 반환함. (비트 XOR 연산)
~ 비트를 1이면 0으로, 0이면 1로 반전시킴. (비트 NOT 연산)
<< 지정한 수만큼 비트들을 전부 왼쪽으로 이동시킴. (left shift 연산)
>> 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴. (right shift 연산)

가변인자

  • 인자의 개수가 정해지지 않았을 때 사용하는 것이 바로 가변인자(variable argument)이다.
  • 함수에서 가변인자를 선언하기 위해서는 …을 이용한다.
  • 함수에 가변인자를 정의하여 그 가변인자를 사용하기 위해서는 라이브러리를 추가해 주어야한다.
    • <stdarg.h> : 가변인자들을 제어하기 위한 라이브러리 헤더 파일
    • va_list : 가변인자 목록으로 가변인자의 메모리 주소를 저장하는 포인터
    • va_start : 가변인자를 가져올 수 있도록 설정
    • va_arg : 가변인자 포인터에서 특정 자료형의 크기만큼 값을 꺼낸다.
    • va_end : 가변인자 처리가 끝났을 때 포인터를 NULL로 초기화해준다.
  • 가변인자를 사용할 때 주의사항
    • 가변인수를 사용하기 위해서는 가변인수의 갯수를 알 수 있어야 하기 때문에 반드시 하나 이상의 고정인자가 필요하다.
      • 가변인수의 크기를 알아야만 함수에서 정확한 제어가 가능하기 때문이다.
      • 고정인자를 통해 함수 내에서 크기를 유추하게 구현 또한 가능하다.
    • 가변인수는 항상 함수의 가장 뒤에 호출이 돼야 한다.
      • 당연히 고정인자와 가변인자를 구분하기 위해서는 가변인자는 뒤에 있어야 한다.
    • 가변인수의 자료형을 명확하게 알아야 한다.
728x90