c90 에서만 해도 배열의 선언시 크기는 반드시 상수여야 했다.
그러나 c99
에서 부터는 배열의 크기를 변수로 지정할 수 있게 되었다.
그러나 이는 사실 원래 가능한 기능이였다. 그런 기능중 하나는 alloca
함수이다.
linux
#include<alloca.h>
void* alloca(size_t size);
alloca
는 malloc과 인터페이스가 같으나, 힙 영역에 할당을 하지 않고 스택영역에 할당 한다.
당연히 할당 속도도 malloc
에 비해 빠르다. 다만 실패시 NULL
을 반환하는 malloc
과 달리 alloca
는 세그먼테이션 오류를 뿜으며 강렬히 전사한다.
VS
#include<malloc.h>
void* _alloca(size_t size);
Visual 에서는 malloc.h
에 정의 되어 있으며, 앞에 _ 가 붙는다. 할당에 실패할경우 Stack over flow를 뿜으며 죽는다.
Windows의 __try 를 사용해 스택오버플로우를 Detect 할 수 있다.
#include<stdio.h>
#include<malloc.h>
#include<Windows.h>
int main() {
__try{
void* p = _alloca(10000000);
printf("success : %p\n", p);
}
__except (GetExceptionCode() == STATUS_STACK_OVERFLOW) {
puts("fail");
}
return 0;
}
이런 alloca 함수도 있으므로 VLA를 선언할 수 있다. 하지만 사용예시가 극히 드물며, 안전성면이나 호환성면에서도 malloc을 사용하는것이 낮다.
(주로 제네릭 프로그래밍을 할때 가끔 사용된다. Swap함수등을 구현할때라던지,)
#include<stdio.h>
int main(){
int n=5;
int arr[n]={0};
return 0;
}
이렇게 변수로 배열의 크기를 지정하는것이 가능하다.
inline
키워드는 더이상 C++에서만 보는 키워드가 아니다.
인라인 함수를 모르는 자가 있는가? 사실 이런 인라인 함수가 있다해도 define
키워드를 많이 사용한다.
더 솔직히 말하면 컴파일러가 알아서 최적화를 해주므로 인라인화에 대해 정확히 모르면 따로 쓸 필요는 없다.
inline void swap(void* a,void* b,size_t size) {
void* tmp = alloca(size);
memcpy(tmp, a, size);
memcpy(a, b, size);
memcpy(b, tmp, size);
}
위의 alloca
와 함께 사용한 인라인 swap 함수이다.
VC에는 __inline
키워드를 사용한다.(언더바가 왜 붙었을까? 하나짜리는 뭐고 두개 붙은건 무엇일까?)
내가 볼땐 언더바가 많이 붙을수록 잘 안쓴다거나....아니면 쓰지말라는 의미인것 같다.
뭐 적을 것도 없다. 더이상 C언어에서도 변수를 아무데서나 선언할 수 있다.
그러나 실제로 C를 프로그래밍 할때 예전 습관떄문인지, 아니면 가독성 때문인지 앞쪽에 선언을 주로 하게 된다.
#include<stdbool.h>
C언어에서도 bool
이라는 자료형이 있다. 하지만 사용하는것은 약간 비 추천한다.
이유는 기존의 C언어 함수들은 bool(True,False) 가 아니라 int(1,0,-1)로 주로 호환되기 때문이다. C프로그래머 역시 그렇고....
vs
#include<complex.h>
_DComplex a; //언더바가 또 붙었네?
linux
#include<complex.h>
double complex a;
http://en.wikichip.org/wiki/c/complex.h
거지같다 정말 ㅡㅡ 실제로 거지 같다.
잘 쓰지도 않는내용이고 만일 쓴다해도, 만들어서 사용하길 바란다. (개인적으로 복소수 필요하면 C++로 짜는것을 권함)
별로 볼것이 없다. 실수와 허수 타입을 모두 지원하겠다는 뜻이다.
제네릭 타입의 매크로를 이용해 double과 complex를 모두 지원하는 수학함수를 만들었다는 뜻인데....말했다 시피 복소수를 쓸일이없기에 이것도 그닥.....
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/tgmath.h.html
에서 자세한 설명을 볼 수 있다. 더군다나 VS에서는 지원도 없다.
VS 는 더이상 C 컴파일러가 아니다. C++ 컴파일러다.
더이상 C++은 C를 하위호환 시키지 않는다.
사실 이것도 별로 볼것이 없다.
먼저 가변인자에 대해 잠깐 짚고 가자.
#include<stdarg.h>
int max(int count, ...) {
int val = 0,m=INT_MIN;
va_list ptr;
va_start(ptr, count);
for (int i = 0; i < count; i++){
val = va_arg(ptr, int);
if (val>m)m = val;
}
va_end(ptr);
return m;
}
위는 최대값을 찾아주는 max 함수이다.
max(5,2,5,1,3,4);
와 같이 사용하며 앞에 반드시 1개 이상의 고정타입인수가 들어가야 한다.
va_list
는 단순한 char*
이고 va_start
로 가변인수 파라매터의 시작 점을 가르키게 하고, va_arg
로 파라매터를 점프한다.
va_end
는 해당 va_list
를 NULL
로 초기화 하여 사용을 끝낸다.
간단하다.
이런 가변인자 함수를 매크로와 쉽게 연결 시키기 위해서 나온게 가변인자 매크로 이다.
#define PRINTF(F,...) printf(F,__VA_ARGS__)
가변인자함수에 인수로 넣을수 있게한다. __VA_ARGS__
가 키워드이다.
뭐야 고작 이거?
아니다. 이런것도 가능하다. 위에서 만든 max 함수의 경우 맨 앞에 반드시 개수를 지정해야 하는 불편함이 있었다.
(이런 불편함이 당신의 실력을 증대 시킬것이다.)
앞의 숫자를 컴퓨터가 계산하게 할 수 없을까? 가 한단계 나아가게 하는 질문이다.
해답은 가변인수들을 문자열로 취급한뒤, 콤마의 개수+1 을 하는것이다.
해답은 아래와 같다.
#include<stdio.h>
#include<stdarg.h>
#include<limits.h>
int max(int count, ...) {
int val = 0,m=INT_MIN;
va_list ptr;
va_start(ptr, count);
for (int i = 0; i < count; i++){
val = va_arg(ptr, int);
if (val>m)m = val;
}
va_end(ptr);
return m;
}
int GetComma(char* s) {
int r = 0;
int b = 0;
while (*s){
if (*s == '(')b++;
if (*s == ')')b--;
if (!b && *s == ',')r++;
s++;
}
return r;
}
#define TO_STR(S) #S
#define MAX(F,...) max(GetComma(TO_STR(__VA_ARGS__))+1,__VA_ARGS__)
int main() {
printf("%d\n", MAX(2,5,1));
printf("%d\n", MAX(3,4));
printf("%d\n", MAX(2,5,MAX(3,6),1));
return 0;
}
매크로에서 앞에 # 을 붙이면 그 매크로는 문자열이 된다.
이제 맨앞 고정인수를 넣지 않아도 된다.
restrict 한정자는 해당 메모리영역을 가르키는 포인터가 단 하나임을 보장하는 키워드로 해당 값을 재 load 하지 않아 컴파일러 최적화에 도움을 주는 키워드이다.
근데...정확하게 이해하지 못하면 아예 사용하지 않는것이 좋다.
쓴다고 엄청 빨라지는것도 아니고 말이다...