반응형

C언어 9

[C11] C언어도 제네릭이? _Generic 키워드 살펴보기

환영합니다, Rolling Ress의 카루입니다. ​ C언어에 제네릭이 이미 들어갔었네요? 물론 C++의 template이나 다른 언어의 제네릭에 비해선 크게 약하지만, 그래도 가능은 하다라는 점에 의의를 두고 싶습니다. C23에서는 아예 auto 키워드가 본래의 의미를 잃고 C++의 auto와 동일하게 변경되는데, C언어도 발전하는 모습이 보기 좋습니다. 그래봐야 실무에선 아직도 C99 쓰겠지만. _Generic(expr, list) 표현식은 간단합니다. 이때 list에는 다음과 같은 것들이 올 수 있습니다. // type은 VLA 또는 VLA를 가리키는 포인터가 올 수 없음. type1: expr1, type2: expr2, default: expr3 C언어는 오버로딩을 지원하지 않기 때문에 매크로의..

C언어 2023.12.31

[C23-] 함수 파라미터에 void를 써야 할까? ─ int func(), int func(void)

환영합니다, Rolling Ress의 카루입니다. ​ 이 글은 C23 이전 표준안에 대해 다루고 있습니다. 사실 아직까지도 C11은 커녕 C99를 주로 쓰는 경우가 많아서, 대부분 이 글에 적용된 내용이 해당됩니다. 한 20년쯤 지나면 이 글이 필요 없어질 수도 있겠군요. 참고로 C++에는 해당이 되지 않는 이야기입니다. C11 이전의 C 표준에서만 해당됩니다. ​ 흔히 C언어에서는 함수를 선언할 때 꼭 void를 쓰라고 합니다. int func(); int func(void); C++ 에서는 위 둘의 뜻이 정확히 같습니다. 매개변수를 받지 않는다는 뜻이죠. 오히려 func(void)보다는 func()를 권장합니다. C# 같은 언어에서는 아예 첫 번째 표현만 가능하고요. (두 번째 표현을 쓰면 오류가 나..

C언어 2023.12.04

[C99] VLA(Variable Length Array; 가변 길이 배열)에 관한 깊은 고찰

환영합니다, Rolling Ress의 카루입니다. ​ C언어를 배우다보면 흔히 이런 말을 한 번쯤은 들어 보셨을 겁니다. 배열을 선언할 때, 크기를 정하는 인덱스에는 변수를 사용할 수 없다. int len = 5; int array[len]; 쉽게 말해서 위와 같은 코드가 불가능하다는 뜻이죠. 일반적으로 상수값만 가능하다고 배우니까. 그런데 이 말은 틀렸습니다. C99부터 VLA라는 문법을 지원하기 때문이에요. C11에서 선택구현으로 바뀌어서 이게 사라졌다고 아시는 분들도 있는데, C23에서 다시 부활했습니다. 아마 C언어는 이 문법을 계속 가지고 갈 것 같아요. ​ * 참고로 이 코드는 gcc에서 C99 이상의 문법으로 컴파일했을 때만 작동합니다. MSVC는 지원하지 않고, C++도 지원하지 않아요. ..

[C11] C언어 표준 스레드 실행

C11에 들어서면서 C언어도 정식으로 스레드를 지원하기 시작했습니다. #include 만 해 주시면 모든 준비가 끝납니다. #include #include #include int func() { thrd_sleep(&(struct timespec){.tv_sec=3}, NULL); puts("func()"); } int main() { thrd_t thread; // 스레드 타입 변수 int result; // 결과값 thrd_create(&thread, func, NULL); thrd_join(thread, &result); printf("result: %d", result); } 간단합니다. C++에서처럼 thrd_t 변수를 선언하고, thrd_create를 통해 스레드를 생성합니다. int thrd..

[C99] Compound Literals, C에서의 이름없는 임시 객체

C++11에서 이름없는 임시 객체 (그리고 이동시맨틱) 때문에 머리가 많이 터졌었죠. 그런데 C에서 비슷한 느낌의 Compound Literals라는 걸 만들었습니다. "한 번만 쓰고 버리는" 변수인데, 배열/구조체/공용체 등에서 사용 가능합니다. 이름없는 임시객체와 비슷한 느낌입니다. (타입){초기화 리스트} 이렇게 사용합니다. 타입에는 배열/구조체/공용체가, 초기화 리스트는 일반 배열 사용하듯이 쓰면 됩니다. C++에서 int(5)이렇게 작성하면 5가 담긴 int형 임시 객체를 생성하는 것 처럼 이것도 마찬가지입니다. (int[]){1, 2, 3, 4, 5} 라고 쓰면 1, 2, 3, 4, 5가 담긴 int형 배열을 만들어냅니다. ​ C++에서는 클래스를 만들고 함수를 호출할 때 이동 시맨틱을 통해 ..

[C99] 포인터 최적화를 위한 restrict 키워드

이 키워드가 추가됨에 따라 , 에서도 알 수 있듯 대부분의 표준 라이브러리 함수들에 restrict가 붙었습니다. 최적화 키워드 중 하나인데, restrict을 쓰면 그 포인터가 가르키는 객체는 다른 포인터가 가르키지 않는다는 것을 나타냅니다. 주로 함수의 매개변수로 쓸 텐데, 예시를 보시죠. #include int int_swap(int* restrict p1, int* restrict p2) { if (p1 == p2) return EOF; int temp = *p1; *p1 = *p2; *p2 = temp; return 0; } int main() { int a = 10, b = 5; printf("a = %d, b = %d\n", a, b); int_swap(&a, &b); printf("a = ..

[C11] 컴파일 타임 오류내기, static_assert

assert() 자주 사용하시나요? 프로그램에서 런타임 오류를 잡아내고 예외를 처리하는데 쓰이죠. ​ 하지만 컴파일 타임에 예외가 있으면 컴파일이 안 되게 만드는, 정적 어설션은 이보다 더 유용할 때가 많습니다. C++에서 static_assert() 키워드를 도입했듯이, C언어에서도 static_assert()를 지원합니다. ​ 물론 C++처럼 네이티브로 지원하는 것은 아니고, 헤더를 하나 포함하거나 살짝 다른 예약어를 사용해야 합니다. _Static_assert(식, 문자열) (C11 예약어) _Static_assert(식) (C2x) #include // 를 하면 static_assert(식, 문자열) // 이렇게 작성해도 됩니다. #include int main() { static_assert(1..

[C99] C언어에서 표준 bool 타입 사용하기

흔히 Boolean 타입은 0과 1만 담을 수 있는, 참/거짓을 판별하는 자료형으로 많이 쓰입니다. C언어에서는 bool 타입이 없어 int를 대신 사용하죠. ​ 그런데 C99....어..그러니까.. 20년 전에 이미 bool타입은 추가되었습니다. 다만 bool이라고 그대로 쓰면 오류가 납니다. 꽤나 나중에 추가된 것이라 그런지 기존 코드에서 호환성을 유지하기 위해서인진 모르겠지만 사용법은 일단 다음과 같습니다. _Bool boolean = 1; 타입 이름은 _Bool입니다. 밑줄 + 대문자는 표준에서만 사용하는 거 아시죠? 그래서 이런 형태로 추가가 됐나 봅니다. 대입은 int형 정수 0, 1을 사용합니다. ​ 하지만 계속 _Bool을 저렇게 안 예쁘게 쓸 수는 없습니다. 그래서 새로운 헤더 파일이 등..

[C11] gets() 대신 get_s()? fgets()? 무엇을 쓸까?

결론: fgets() 쓰세요. ​ C11이 되면서 보안상 엄청난 결함을 가지고 있던 gets() 함수가 드디어 삭제되었습니다. 이제 최신 컴파일러에서는 gets()를 사용할 수 없습니다. 사용할 수는 있어도 보안 경고가 뜰 겁니다. 비주얼 스튜디오에서는 get_s()를 사용하라고 하는군요. 그런데, gets_s()는 표준이긴 하지만 optional이라 지원되지 않는 컴파일러도 꽤 있는 것으로 알고 있습니다. 그래서 대부분은 fgets()를 더 추천하죠. ​ 두 함수의 원형은 이렇습니다. char *gets_s( char *str, rsize_t n ); // C11 부터, 선택사항 char *fgets( char *restrict str, int count, FILE *restrict stream ) /..

반응형