Chapter 18. Declarations

지환·2022년 2월 17일
0
post-custom-banner

18.1 Declaration Syntax

Declaration은 identifier의 의미를 compiler에게 알려준다.

declaration-specifiers declarators ;
Dclaration은 위 구조를 가진다.
한 파트씩 차근차근 보자.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
Declaration-specifiers는 선언되는 변수(or함수)의 특징을 알려준다. 이는 아래 네가지 카테고리로 나눠진다.

  1. Storage classes

    1. auto
    2. static
    3. extern
    4. register

    최대 하나의 storage class만 제일 앞에 올 수 있다.

  2. Type qualifiers

    1. const
    2. volatile
    3. restrict

    0개 이상 포함할 수 있다.

  3. Type specifiers

    • void, char, short, int, long, float, double, signed, unsigned

    chapter 7에 설명했듯이 아무 순서로 와도 되고 조합될 수 있다. structure, union, enumeration도 여기에 포함된다. typedef로 만든 type도 여기에 포함된다.

  4. Function specifier

    • inline

Storage class만 제일 앞에 오고 나머지 Type specifier과 Type specifier의 순서는 상관없다.
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
Declarators는 변수(or함수)의 이름과 추가적인 정보를 알려준다.

  1. identifiers (name of simple variable)
  2. identifiers followed by [] (array name)
  3. identifiers followed by () (function name)
  4. identifiers preceded by * (pointer name)

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
함수든 변수든 위 규칙대로 Declare 할 수 있다.


18.2 Storage Classes

variable의 storage class에 집중해서 우선 보자

if, switch, for, do, while 이런 애들도 전부 통째로 block으로 여겨진다. (자세한건 chapter 10에 내가 정리해둠. 책은 p.475 참고)

Properties of Variables

  1. Storage duration
    automatic storage duration : block이 시작할 때 할당되고, 끝날 때 deallocate된다.
    static storage duration : 프로그램 돌아가는 내내 storage location을 유지한다.
  2. Scope
    variable이 어디서 referenced 될 수 있는지를 알려준다.
    block scope : declare된 point부터 block이 끝날 때까지 visible
    file scope : declare된 point부터 file이 끝날 때까지 visible
    (Chapter 10의 scope rule도 다시 한번 봐주면 좋음)
  3. Linkage
    variable이 program의 다른 part와 어느 정도 범위까지 확장될 수 있는지 알려준다.
    external linkage : 그 프로그램 내의 여러 파일들과 공유될 수 있다.
    internal linkage : 하나의 파일 내에서만 공유된다.(이 경우 다른 파일에서 같은 이름이 보이면 이는 다른 변수로 취급된다.)
    no linkage : 하나의 함수 내에서만 공유된다.
    internal linkage? no linkage? :
    https://stackoverflow.com/questions/24864840/difference-between-internal-and-no-linkage

변수가 어디에 선언됐는지에 따라 변수에 대한 특징 세가지가 기본적으로 정해진다.

  • block 안에서 선언됐다면,
    automatic storage duration
    block scope
    no linkage
  • block 밖에서 선언됐다면,
    static storage
    file scope
    external linkage

Storage class를 명시함으로써 위 세가지 특징을 바꿀 수 있다.

The auto Storage Class

block안에서 선언된 variable에 사용할 수 있다.
얘를 쓰면 automatic storage duration, block scope, no linkage가 된다.
그래서 전혀 쓸 필요가 없다. 왜냐하면 block안에서 선언됐으면 그냥 저 특징대로 되기 때문이다.

The static Storage Class

얘는 어디서 선언됐든 사용할 수 있다.

block 밖에서 선언된 변수에 static을 적용하면
static storage duration
file scope
internal linkage
가 된다. (linkage 빼고는 그대로) (information hiding에 사용)

block 안에서 선언된 변수에 static을 적용하면
static storage duration
block scope
no linkage
이 된다. (storage duration 빼고는 그대로)

static 변수가 가지는 특징

  • 프로그램 실행 전에 variable을 한번 initialize한다. (반면 auto는 기회가 있으면 매번 초기화 한다.)
  • 함수가 재귀호출될 때, auto는 계속 변수를 만들지만, static은 변수를 모든 함수 호출과 공유한다.
  • 당연히 포인터 변수로 반환해줘도 메모리가 유지되므로 OK
char digit_to_hex_char(int digit)
{
	static const char hex_chars[16] = "0123456789ABCDEF";
    //storage class는 제일 앞에 와야됨
    return hex_chars[digit];

이렇게 매번 호출되는 함수의 변수를 static을 활용해 한번만 initialize되도록 할 수 있다. 이렇게 속도를 올릴 수 있다.
(static 없으면 호출될때마다 매번 hex_char가 생성돼 효율 떨어짐)

The extern Storage Class

15.2에서 이미 본질적인 부분이 나왔다.
프로그램내에 variable의 declaration은 많아도 되지만 definition은 하나만 있어야 한다.

여러 파일에서 변수를 공유하기 위해 declare 만하려고 extern을 사용한다. (메모리 할당 안됨)
extern int i = 0;
이렇게 extern이 initializer와 함께 쓰이면 이는 함수의 definition이다. int i = 0; 얘와 같다.

extern을 사용하면
static storage duration, (다른 파일과 공유하는게 주 목적인데 static이 아니면 의미가 없음)
scope는 위치에 따라 정해진다.
그리고 linkage는, file 내에서 static으로 정의돼있으면 internal linkage고, 그게 아니면 external linkage이다.
(external이 디폴트고, static있으면 internal이 되는거임)

(다른 file에 static으로 정의돼있으면 그건 얘랑 이름같아도 그냥 다른 변수라서 생각할 필요없음. 같은 file 내에서 static으로 선언됐으면 얘도 그거에 맞춰서 internal linkage로 가는건 당연하다. 이 파일 내에서 static으로 선언된게 아니라면, 다른 파일과 공유돼야하니 위에서 static storage는 해주니까 external linkage까지 해서 다른 파일과 공유될 수 있게 맞춰주는거지) (stoarage class는 선언할 때 하나밖에 못오니까 static으로 선언됐다고 하는건 static int i; 이런식으로 돼있을 것이란 소리다. 여기다 storage class는 뭘 더 못붙임.)

이런 'extern' keyword는 헤더파일에서 변수 declare할때 사용
함수는 어차피 declaration만 헤더에 넣기때문에 extern 의미없고,
변수는 extern 없이 쓰면 declare가 아니라 definition이라 헤더에선 extern 해줘야됨.
헤더 안쓰고 그냥 같이 컴파일되는 다른 소스의 extern linkage 변수 참조할 수도 있는데,
이때도 그냥 extern으로 선언해주면 된다.

The register Storage Class

(17.8의 restricted pointer처럼 최적화 역할을 한다.)

resgister storage class를 사용하면 해당 변수를 main memory가 아니라 register에 저장하도록 compiler에 요청한다.
(말 그대로 요청일 뿐 무조건 이뤄지는게 아니다.)

register : CPU 내의 저장공간이다. 다른 메모리에 비해 접근과 사용이 빠르다.

auto처럼 block안의 variable에만 적용할 수 있다.
그래서 auto와 같은 storage duration, scope, linkage를 가진다.

대신 register는 주소가 없기 때문에 & operator를 사용하는 것이 금지된다.
(compiler가 register에 저장하지 않고, 그냥 memory에 저장했더라도 이는 금지된다.)

자주 accessed되고, 자주 updated되는 변수에 적용하면 좋다.
예를들어 for statement의 control variable..

요즘엔 compiler가 알아서 뭐가 register에 들어가면 좋을지 잘 판단하기때문에 옛날만큼 많이 쓰이진 않는다. 그럼에도 적어주면 최적화 하는데 도움이 될 수 있다.

포인터로 접근/수정이 안된다는 점에서 retirct와 어느 정도 연관이 있다.

The Storage Class of a Function

  1. extern : 함수를 external linkage로 만들며 다른 file에서 호출할 수 있게 한다.
  2. static : 함수를 internal likage로 만들며 함수가 정의된 file내에서만 사용할 수 있게한다. (function pointer를 이용한 간접적 호출은 허용된다.)

둘중에서 사용할 수 있다.

만약 함수에 표시된 storage class가 없다면, external linkage로 간주한다.
그래서 extern을 적는건 사실상 변수에 auto를 적는거나 마찬가지라서 안적어도 상관 없다.

반면에static은 꽤 유용하다.
어떤 함수를 다른 파일과 공유할 목적이 없다면 static으로 선언하는 것이 좋다.
Easier maintenance : static으로 선언됐으면 해당 함수 내에서만 쓰였다는걸 쉽게 알 수 있어서 수정하기 쉽다. 다른 파일에서 함수 포인터로 해당 함수를 사용할 수도 있지만, 어차피 static 함수가 정의된 파일 내에서 넘겨줬을 것이니 알아보기 어렵지 않다.
Reduced "name space pollution" : 해당 함수 이름을 다른 함수에서 또 써도 OK. 일부러 같은 이름을 쓰진 않겠다만 큰 프로그램에선 그렇지 않기가 어렵다.

함수 parameter는 auto variable과 같은 특징을 가진다.
(automatic storage duration, block scope, no linkage)
parameter에는 register storage class 명시될 수 있다.

Summary

int a;
extern int b;
static int c;

void f(int d, register int e)
{
	auto int g;
    int h;
    static int i;
    extern int j;
    register int k;
}
NameStorage DurationScopeLinkage
astaticfileexternal
bstaticfile?
cstaticfileinternal
dautomaticblocknone
eautomaticblocknone
gautomaticblocknone
hautomaticblocknone
istaticblocknone
jstaticblock?
kautomaticblocknone
여기서 '?'로 된 거는 딱 이 code만 놓고 보면 external linkage인데,
위에 static으로 선언된 같은 이름의 변수가 있다면 internal linkage이다.

18.3 Type Qualifiers

아래 3개의 Type Qualifiers가 있다.

  1. const
  2. volatile
    : low-level 프로그래밍에서만 사용할 수 있어서 그때 자세히... (Section 20.3)
  3. restrict
    : 앞에서 다 얘기했다..(Section 17.8)

const Type Qualifier

const int n = 10;
const int tax_brackets[] = {500, 1000, 1500};
"read-only" object를 선언하기 위해 사용된다.
access는 가능하지만, 수정은 안된다.

장점
1. code를 읽는 사람에게 해당 변수가 read-only인 것을 알려준다.
2. object 값을 수정하려는 것을 compiler가 check한다.
3. embedded system 같은 응용프로그램을 작성하려고 할때 data가 ROM(ReadOnlyMemory)에 저장된다고 표시할 수 있다.

#define과의 차이?
1. #define은 numerical, character, string 의 이름을 작성하는데 사용될 수 있지만,
const는 array, pointer, structure, union 등등 아무 type이나 read-only object로 만들 수 있다.
2. const는 해당 변수의 scope rule을 따른다.
3. const object는 debugger에 보인다.
4. macro와 달리 const object는 constant expression으로 쓰일 수 없다.
예를들어 array 의 크기에 const object가 올 수 없다.(C99부터는 automatic storage duration이라면 VLA가 되기때문에 올수 있다.)
5. const object는 주소가 있기 때문에 & operator를 사용할 수 있다. macro는 물론 안된다.

상수 아닌걸로 initialize해도 OK
initializer에 상수가 와야되는건 storage duration의 문제이다.


18.4 Declarators

declaration-specifiers declarators
에서 뒷부분인 declarators에 대해 알아보자.

위에서 말했듯이 declarators
identifier or plus * or [] or ()
로 구성된다.

  • *이 앞에 오면 pointer다.
  • []가 뒤에 오면 array다.
    array가 parameter이거나, initializer가 있거나, storage class가 extern이면, bracket은 비어있어도 된다.
    (추가로 2차원 배열일때 첫번째 []는 비어있어도 된다.)
    array가 parameter에 있을 때, bracket 안에 올 수 있는 option은 두가지인데, static*이다.
    static은 parameter에서 배열의 최소 길이를 명시해주고
    *은 VLA argument임을 나타낼 때 사용할 수 있다.
  • ()가 뒤에 오면 function이다.
    function declaration에선 parameter name을 생략해도 된다.
    심지어 parentheses가 비어있어도 된다. 그러면 parameter가 없는게 아니라, 그저 parameter의 정보를 제공하지 않는 것 뿐이다. void 라고 적어넣어야 parameter이 없는 것.(declaration에서만 해당되는 얘기임) (함수 호출 때 제대로 된 argument 넘겼는지 확인할 수 없어서 이 방식은 거의 사라짐)

Deciphering Complex Declarations

  1. Always read declarators from the inside out
    : indentifer로부터 파악해나가기 시작한다.
  2. When there's a choice, always favor [] and () over *
    : *보단 []()가 먼저다. *[]가 같이있으면 그건 포인터가 아니라 배열을 나타낸다는 뜻 (물론 괄호를 이용해서 우선순위를 바꿀 수도 있다.)

int *ap[10]; : array of pointer
float *fp(float) : float * 을 return 하는 함수
float (*fp)(float) : 괄호가 있어서 우선순위가 바뀌니까 얘는 포인터(float을 반환하고 float을 입력으로 받는 함수 포인터)
int *(*x[10])(void); : int *을 반환하고 argument가 없는 함수를 가리키는 포인터의 배열

배열를 return 하는 함수,
함수를 return 하는 함수,
함수의 배열
은 선언할 수 없다.

Using Type Definitions to Simplify Declarations

int *(*x[10])(void);

typedef int *Fcn(void);
typedef Fcn *Fcn_ptr;
typedef Fcn_ptr Fcn_ptr_array[10];
Fcn_ptr_array x;
변수명 위치에 온걸로 typedef됨

이렇게 type으로 선언해두면 편하게 쓴다.
간단 예시


18.5 Initializers

assignment에서의 =와는 다르다.
즉, 아래 경우는 initialize할때를 말하는거지 assign 할때는 적용되지 않는다.

  • initializer와 type이 맞지 않으면 assignment에서와 같은 rule을 적용한다.
  • pointer변수의 initializer는 같은 type의 pointer expression이거나 void *이어야 한다.
  • array, structure, union의 initializer는 대부분 {}로 이루어져있다.(designated initializer까지 해서..)
  • array, structure, union의 brace-enclosed initializer는 무조건 constant exrpessoin만 포함해야한다.(C99부턴 아니다. 꼭 constant로 해야되는건 static storage duration인 경우밖에 없다.)
  • static storage duration의 variable은 무조건 constant로 initialize돼야 한다.(C99 6.7.8 : ...constant expression이거나 string literal이어야한다...)
    (주의: global varaible은 자동으로 static storage duration이라 무조건 constant expression으로만 초기화해야됨)
  • automatic storage duration이면 꼭 constant가 아니라 변수가 중간에 섞여있어도 괜찮다.
  • structure나 union이 automatic storage duration이면 braces가 아니라 적당한 type의 다른 expression이 와도 된다.

static storage class 의문점
1. initialize할때 왜 꼭 constant expression이 와야하지?
: C99 5.1.2에 의하면 static storage duration은 프로그램 start up전에 initialize 돼있어야 한다. constant가 아니라 그냥 variable이면 값이 실행중에 결정되기 때문에 startup전에 initialize될 수 없다.(그래서 우리가 따로 초기화하지 않으면 아래 나와있듯이 0으로 초기화 되는거다.)
2. 그럼 assign할때는 왜 constant expression이 아니어도 되지?
: 이미 startup전에 초기화 된 값을 수정만 하는건데 굳이 constant exrpession일 필요는 없다. 프로그램 실행중이니 variable이 와도 상관없다.
3. global variable을 함수 밖에서 assign하니까 오류가 뜬다 뭐지?? assign하는건 상관없다고 안했나???
: 함수밖에서는 assign하면 안된다.. 애초에 함수 밖에는 그냥 일반적인 exrpession code가 올 수 없다. 걔네가 함수 안에 있는 것도 아닌데 실행 순서를 알 수가 없다..
자세한 답변은 https://stackoverflow.com/questions/50661263/why-cant-i-assign-values-to-global-variables-outside-a-function-in-c

Uninitialized Variables

unitilized varaible의 값은 storage duration에 따라 결정된다.

  • automatic storage duration : default initial value가 없다. 그래서 예측할 수 없다.
  • static storage duration : zero 를 default 값으로 가진다. calloc이 모든 bits를 0으로 만드는 것과 다르게 실제 값을 0으로 만들어 준다. integer면 0, float이면 0.0, pointer면 null pointer로 만들어 준다.
    그래도 이걸 믿고 그냥 초기화 안하고 0으로 쓰기보다는 귀찮더라도 초기화 해주는 편이 낫다.
    (C99 5.1.2에 의하면 static storage duration은 프로그램 start up전에 initialized 돼있어야 한다. 그래서 이렇게 특정 값으로 initialize하는듯)

18.6 Inline Functions (C99)

declaration-specifiers declarators
Declaration-specifiers 중 function specifier에 해당하는 inline에 대해 알아보자.

inline을 이해하기 위해 C compiler에서 함수가 호출되고 반환되는 machine instruction을 알아볼 필요가 있다.
함수를 호출하게 되면 함수 시작지점의 instruction으로 이동해서 실행하고 다시 돌아오게 된다.
(argument있으면 copy하고.. 등)
이런 함수의 기본적인 기능 외에 추가적인 작업을 overhead라고 하는데, 이걸 없애기위해 inline을 사용한다.
(C89에선 parameterized macro 사용했는데, 결점이 있었음)

inline을 사용하면 함수 호출 부분을 해당 함수의 machine instruction으로 compiler가 대체한다.
그래서 이걸 많이 사용하면 파일 크기가 커진다.
이것도 restrictregister처럼 command가 아닌 suggestion에 불과하다.

Inline Definitions

inline int sum(int a, int b)
{
	return a + b;
}

주의 : 이렇게 inline으로 선언돼도 특별한게 없으면 external linkage이긴 하지만, external definition이 아니라 inline definition으로 보고, 다른 파일에서 이 함수를 사용하지 못한다.(error)

external definition이란? 그냥 함수 밖에서 선언된 함수 혹은 object(inline definition 제외)
이 external definition이 있어야 다른 파일에서도 함수 호출이 가능함.

대안

  1. inline함수는 아예 static 키워드를 포함시켜서 internal linkage임을 확실히 하자.
    (C99에 보면 internal linkage면 external definition 포함하라고 돼있는데..? -> C99 다시 잘 보면 inline function과 inline definition을 구분해서 말하는 것 같음, 그렇게 구분해서 보면, static 포함한 internal linkage는 inline definition이 아니라서 상관없는 것 같은데.. 잘 모르겠네 뭐 집착할 필욘 없지싶다.)

  2. inline을 포함하지 않는 external definition을 다른 파일에 포함시키는 방법도 있다.(이러면 inline함수 정의가 없는 다른 파일들은 inlining되는게 아니라 그냥 함수호출하는 방식이겠지?) legal이긴 하지만, 두 버전이 일관되는지 보장하기 어려워 좋은 아이디어는 아니다.

  3. header file에 inline definition을 포함시킨다. 그리고 해당 함수가 필요한 파일에서 include 한다.
    그리고 extern keyword를 활용해서 external definition을 만든 후, 그 external definition이 있는 source file에 header file을 include해서 두 버전이 일관성을 가지도록 한다.
    (자세한 구현은 p.474)

    inline 공부하면서 들었던 의문점들 이 문서 최하단에 나름 정리해둠

Restrictions on Inline Functions

일반적인 함수와는 실행되는 방식이 달라서 몇가지 제한 사항이 있다.

external linkageinline 함수는 아래 rule을 따른다.(internal linkage면 상관없음)

  • The function may not define a modifiable static variable.
  • The function may not conatain references to variable swith internal linkage.

수정가능한 static은 안되니까, staticconst를 사용해서 변수를 선언하면 OK
(그러나 인라인 정의 각각이 그 변수의 복사본을 생성할 수 있음) (보통 함수 하나 정의해서 static const 쓰면 그 변수가 가리키는 하나의 object만 컨트롤 하는데, inline의 경우 함수마다 변수가 따로 놀 수도 있다는 뜻인듯)

Using Inline Functions with GCC

gcc 같은 몇몇 컴파일러들은 inline이 표준에 있기 전부터 지원해왔다.
그래서 사용법이 위에서 설명한 것(표준)과 좀 다를 수 있다.
자세한 설명은 p.475 참고...


Q&A

selection statement, iteration statement가 block인 이유?
책엔 p.475에 있고, 블로그엔 chapter 10에 정리해둠. 간단하게만 말하자면, compound literal의 storage duration 일관성을 유지하기 위해 selection, iteration statement 전체를 block으로 봄.

automatic storage duration이면 block이 시작될 때 memory가 할당된다고 했는데, VLA도 마찬가지 인가?
No, block 시작할 때는 length를 모르기 때문에 할당할 수 없다. VLA declaration에 도달했을 때 할당된다. 이런 관점에서 볼때 VLA는 다른 automatic storage duration과 다르다.

scope와 linkage는 정확히 어떤 차이?
본문 linkage 설명에 걸린 stackoverflow 답변에서도 그 차이를 볼 수 있는데(scope는 그 변수가 어디까지 보이냐.. linkage는 두 변수가 같은 이름을 가지면 linkage 범위에 따라서 같은 object를 나타낼 것이냐..),
하나 더 설명하자면..
scope는 compiler의 편의를 위한거고, linkage는 linker의 편의를 위한 것이다. scope를 통해 compiler는 file 내에서 해당 변수가 사용될 수 있는지 판단한다.
그렇게 compiler가 source file을 object code로 만들고,,,
만들때 external linkage들을 표시함으로써 linker에게 internal linkage와 no linkage는 보이지 않고 external linkage만 보이게 된다.
(그럼 이 no linkage와 internal linkage의 차이는? -> 링크)

const object는 constant expression에 쓰일 수 없나? const의 의미가 constant 아닌가?
C에서 const의 의미는 constant가 아니라 "read-only이다.

const object를 constant expression에 사용하도록 허용하면 생기는 문제 예시를 들어보겠다.
1. const object는 그 lifetime 동안만 constant이다.

void f(int n)
{
	const int m = n;
    
    switch(...) {
    	case m : ...    //WRONG
	}
}

m은 함수가 실행될때까지 알 수 없다. 근데 constant expression이어야 하는 switch문의 label이 저런 식으로 선언되면 안된다.
2. 함수 밖에서 선언돼, 그 lifetime이 길어져도 문제는 여전히 남는다.

extern const int n;
int a[n];	//WRONG

n이 다른 파일에 정의돼있는 변수라면, 컴파일러가 a의 길이를 정의하는 것은 불가능하다.
(a는 (external variable일테니) static storage duration을 가지는데 그럼 a는 VLA도 될 수 없다.(p.175))
3. extern const volatile int real_time_clock;
심지어 volatile을 같이 사용하면 프로그램 실행 중에 값이 바뀔수도 있다.(const로 선언됐으므로 프로그램에 의해 바뀌는게 아니라, 다른 메커니즘에 의해 바뀔 수 있음)

declarator의 문법이 이상해보임
declarator는 그 사용을 흉내내려는 의도로 만들어졌다.
int *p; 같은 포인터 선언은 *p라는 indirection operator를 적용하는 것과 비슷하고,
int a[~] = {~};a[~]는 array subscripting과 비슷하다. 함수도 마찬가지로 선언과 호출이 비슷하게(혹은 같게) 생겼다.
좀 복잡한 형태로 돼있는 declarator도 선언할때와 사용할때의 *, parantheses, brackets 위치가 같다.


inline 함수 공부할때 궁금했던 점...
일단 external definition이라는 단어를 여기서 처음 봤다.
그게 뭔지 C99 문서에 찾아보니, 대충 "함수 밖에서 declare되고 define된 함수나 object"라는데 중요한건 괄호에 "inline definition은 제외"라고 적혀있다.(1번)
그리고 (2번)저 말이 적혀있는 같은 장에 "internal linkage로 함수 선언해서 사용하려면 external definition이 있어야된다"고 한다.
근데 (3번)knk에선 inlineexternal linkage로 쓰면 오류 생기니까 그 대안으로 static을 쓰란다..(위에 보면 대안으로 나옴)

아니 그럼 여기서 궁금한게... 1번, 2번, 3번을 합쳐서 보면,
3번에서 inlinestatic을 붙이면 internal linkage가 된다.
여기서 2번을 적용하면 해당 함수는 internal linkage니까 external definition이 있어야 된다.
근데 1번을 보면 inline definitionexternal definition이 아니란다...

그러면 knk에서 static을 적용하는게 대안이라고 말할때,
external definition을 선언해야 되지않나?
라고 생각하게 되었다.
그래서 stackoverflow고 뭐고 다 뒤져봤는데 명확한 답변이 없었다. 내가 너무 쓸데없는걸 생각하나? 싶기도한데 성격이 이런데 어쩌겠누..ㅋㅋ

고민하고 고민하다가 C99문서를 다시 자세히 읽어보니..
inline definitioninline function을 구분해서 말하는 듯 했다.
inline definition은 external linkage에서 선언한 경우에만 해당되는 것이다.(정확한진 모르겠다..)

나름대로 둘이 구분된다고 생각하고 C99에 나온 용어 그대로 정리를 해봤다..


inline specifier로 선언된 함수를 inline function이라고 함

inline function으로 만드는건 함수 호출을 최대한 빨리 하도록 제안하는 것

아무 internal linkage인 함수는 inline function이 될 수있다.

하지만 "external linkage"라면 몇몇 제한사항이 적용된다.(아래는 그럼 다 external linkage인 경우네..)
같은 UT에서 또 정의될 수 있다.
파일 내에 전부 다 extern 키워드 없이 inline만 쓰면 이를 inline defintion 이라고 한다.(이거도 external linkage인 경우라고 보면 맞네, 위에서 external linkage의 제한사항 이라고 했으니까..?)
inline definitionexternal definition을 제공하지 않는다.
그리고 다른 UT에 external definition이 정의되는 것을 막지도 않는다.
inline defnitionexternal defition 중에 뭘 쓸지는 모른다. (external definition 필요한 이유 1)
C99 6.9 5에 external linkage가 exrpession에 쓰이려면 external definition 필요하다고 한다. (external definition 필요한 이유 2)

external linkage인 inline definition에서 어떻게 external definition을 만드나..? -> extern 키워드 활용 ㅎㅎ

이게 맞는진 모르겠는데 두 용어를 다르게 보고 해석하면 대충 들어맞는 것 같다.

결국 knk에서 오류가 뜨는 이유는 external likage에서 inline으로 선언해서 inline definition이 있었기 때문이고,
이 대안으로
1. internal linkage로 만들어버리거나(이러면 inline definition 아님, 그리고 위에서 설명했듯이 다른 파일에서 호출 불가)
2. 그냥 external definition을 만드는 방법이 있다.
근데 2번 방법은 2가지 방법이 있어서 knk에서 따로 설명한 것 같다.

post-custom-banner

0개의 댓글