[C] C11
C11에 새롭게 추가된 문법들을 소개한다. 아쉽지만 Windows에서는 C11을 제대로 지원하는 무료 컴파일러는 없다. ICC가 지원한다고는 하나 확인해 보진 못했고 유료이다.
매우 아쉽게도 c11을 제대로 사용하려면 Linux로 가야한다.
_Noreturn, noreturn
_Noreturn
또는 noreturn
키워드는 c11표준으로 등장했다.
이 키워드는 해당 함수가 컴파일러에게 반환값이 없음을 명시하여 최적화에 도움을 준다.
예를들어 아래 fatal함수같은 경우는 절대로 반환값이 나올 수 없다.
#include <stdlib.h>
#include <stdio.h>
#if defined(__STDC_VERSION__) && __STDC_VERSION__>=201112
# include <stdnoreturn.h>
# if defined(_WIN32) || defined(_WIN64)
# define NORETURN __declspec(noreturn)
# else
# define NORETURN noreturn
# endif
#else
# define NORETURN
#endif
NORETURN void fatal(void)
{
fprintf(stderr,"error message\n");
exit(1);
}
int main(void)
{
int i = 1;
if(i%2)
fatal();
puts("This code is never executed.");
}
c11이 지원되는 컴파일러의 경우 stdnoreturn.h
을 사용하고 Visual Studio의 경우는 _-declspec(noreturn)
을 사용하면 된다.
_Alignof, _Alignas, alignas, alignof
_Alignas
또는 alignas
키워드는 해당 변수(의 시작주소)가 지정한 상수배수의 위치에 정렬되도록 한다. 이는 구조체의 패딩과도 관련이 깊다. 구조체의 패딩을 결졍하는것이 아니라 해당 변수에게만 지정된 상수의 배수 주소에 선언하게 하는 키워드이다.
이 키위드를 이해하기 전에 구조체 패킹 키워드인 __attribute__((__packed__))
과 #pragma pack(N)
부터 제대로 알고 가야 한다.
__attribute__((__packed__))
과 __attribute__((packed, aligned(N)))
은 struct를 선언할 시 struct 키위드 뒤에다 사용하면 된다.
아래의 2가지 방법 모두 사용 가능하다.
struct Z{
char a;
int b;
float c;
}__attribute__((packed, aligned(1)));
struct __attribute__((packed, aligned(1))) Z{
char a;
int b;
float c;
};
또한 __attribute__((__packed__))
과 __attribute__((packed, aligned(1)))
은 동일하다.
이 키워드는 구조체의 정렬 옵션을 제한한다. 구조체 내부의 모든 변수를 지정된 정렬배수에 맞추어 메모리 구조를 할당한다.
#pragma pack(N)
역시 마찬가지이다. 이 또한 구조체 내부의 모든 변수를 지정된 정렬배수에 맞추어 메모리 구조를 할당한다.
이제 _Alignas
키워드를 살펴 보자. 이 키워드는 해당 변수를 지정된 정렬 배수에 맞추어 메모리 구조를 할당한다.
당연히 나머지 변수의 키워드는 __attribute__((packed, aligned(N)))
에서 지정한 대로 동작한다.
하지만 #pragma pack()
을 사용했을 경우에는 _Alignof
는 무시된다.
그러니까 우선순위를 정리하자면
#pragma pack()
과 __attribute__((packed, aligned(N)))
를 같이 사용하면 pragma pack 무시됨.
#pragma pack()
과 _Alignas
를 같이 사용하면 _Alignas 무시됨.
_Alignas
와 __attribute__((packed, aligned(N)))
는 같이 사용 가능. 여기서 _Alignas로 지정하지 않은 변수는 __attribute__((packed, aligned(N)))
에서 지정한 정렬 배수를 따라가지만 _Alignof
키워드에서는 가장 큰 _Alignas
정렬 배수를 출력한다.
소름돋는 결과인 3가지 키워드를 모두 사용하면 #pragma pack
에 의해 _Alignas
는 무시되고
__attribute__((packed, aligned(N)))
에 의해 pragma pack
은 무시되어서
__attribute__((packed, aligned(N)))
만 남게 된다.
이미 선언된 구조체의 정렬 배수를 알고 싶다면 _Alignof
를 사용한다.
#include<stdio.h>
#include<stdalign.h> //alignas, alignof
#include<stddef.h> //offsetof
struct Z{
alignas(4) char a[10];
alignas(8) int b;
char c;
float d;
}__attribute__((packed, aligned(1)));
int main(){
printf("sizeof = %ld\n",sizeof(struct Z));
printf("alignof = %ld\n",alignof(struct Z));
printf("offsetof a = %ld\n",offsetof(struct Z,a));
printf("offsetof b = %ld\n",offsetof(struct Z,b));
printf("offsetof c = %ld\n",offsetof(struct Z,c));
printf("offsetof d = %ld\n",offsetof(struct Z,d));
return 0;
}
_Exit
이 함수는 자원을 정리하지 않고 그냥 프로세스를 종료한다. 즉, int atexit( void (*func)(void) );
함수나 int at_quick_exit( void (*func)(void) );
를 호출하지 않는다.
이게 왜 C11이냐? 함수 프로토타입이 바뀌었다. 리턴값이 없으므로 함수 원형이 아래와 같이 바뀌었다.
_Noreturn void _Exit( int exit_code );
_Pragma
_Pragma(string-literal)
은 이미 알고 있는 #pragma
와 동일하다.
왜 있는지 모르겠다.
#include<stdio.h>
#include<stdalign.h> //alignas, alignof
#include<stddef.h> //offsetof
_Pragma("pack(1)") //same as #pragma pack(1)
struct Z{
char a[10];
int b;
char c;
float d;
};
int main(){
printf("sizeof = %ld\n",sizeof(struct Z));
printf("alignof = %ld\n",alignof(struct Z));
printf("offsetof a = %ld\n",offsetof(struct Z,a));
printf("offsetof b = %ld\n",offsetof(struct Z,b));
printf("offsetof c = %ld\n",offsetof(struct Z,c));
printf("offsetof d = %ld\n",offsetof(struct Z,d));
return 0;
}
func
함수 이름을 지정하는 문자열 값의 매크로이다.... 기존에 있던 __FUNCTION__
과의 차이는 모르겠다.
#include<stdio.h>
void foo(){
puts(__func__);
}
void bar(){
puts(__FUNCTION__);
}
int main(){
printf("%s\n",__func__);
foo();
bar();
return 0;
}
_Generic
매크로 관련 키워드이다. 아래와 같이 사용하며 이를 이용한 제네릭 프로그래밍이 가능하다.
#include<stdio.h>
void foof(float v){
printf("float value v is : %f\n",v);
}
void fooi(int v){
printf("int value v is : %d\n",v);
}
void food(double v){
printf("double value v is : %f\n",v);
}
#define foo(V) _Generic((V),float: foof,int: fooi,double: food,default: fooi)(V)
int main(){
foo(5);
foo(4.4F);
foo(4.7);
return 0;
}
Author And Source
이 문제에 관하여([C] C11), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@springkim/C-C11저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)