[C] 문자열 유사클래스 구현

언어/C 2018. 12. 30. 21:20

oop 흉내.


C의 한계로, 메서드마다 첫번째 인자로 객체 자신의 주소를 보내줘야 함.


https://github.com/myyrakle/c-oop-string/blob/master/main.c


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
 
//기본 초기화 목록입니다.
//기본 빈 값을 넣어주고,
//유사 멤버함수들을 전부 넣어줍니다.
#define NullString \
{ \
NULL0, \
_string_set, \
_string_setn, \
_string_gets, \
_string_get_length, \
_string_copy_from, \
_string_clone, \
_string_move, \
_string_append, \
_string_append_raw, \
_string_swap, \
_string_clear, \
_string_is_empty, \
_string_compare, \
_string_compare_raw, \
_string_is_same, \
_string_is_same_raw, \
_string_format, \
_string_append_format, \
_string_at, \
_string_ptr_at, \
_string_findc, \
_string_finds, \
_string_finds_raw, \
}
 
 
//C스타일 문자열 유사클래스입니다.
struct String
{
    char* data;
    size_t length;
 
    //문자열을 할당합니다.
    void (*set)(struct String*const char*);
    void (*setn)(struct String*const char*, size_t);
 
    //문자열을 가져옵니다.
    const char* (*gets)(const struct String*);
 
    //문자열의 길이를 가져옵니다.
    size_t (*get_length)(const struct String*);
 
    //깊은복사를 행합니다.
    void (*copy_from)(struct String*const struct String*);
 
    //깊게 복제된 객체를 반환합니다.
    struct String (*clone)(const struct String*);
 
    //이동합니다. 자신은 clear가 됩니다.
    struct String (*move)(struct String*);
 
    //이어붙입니다.
    void (*append)(struct String*const struct String*); //String 버전입니다.
    void (*append_raw)(struct String*const char*); //생 문자열 버전입니다.
 
    //교환합니다.
    void (*swap)(struct String*struct String*);
 
    //지워버립니다.
    void (*clear)(struct String*);
 
    //비어있는지 여부를 확인합니다.
    int (*is_empty)(const struct String*);
 
    //비교해서 같으면 0... 뭐 그런거요
    int (*compare)(const struct String*const struct String*); //String 버전입니다.
    int (*compare_raw)(const struct String*const char*); //생 문자열 버전입니다.
 
    //같으면 1. 다르면 0.
    int (*is_same)(const struct String*const struct String*); //String 버전입니다.
    int (*is_same_raw)(const struct String*const char*); //생 문자열 버전입니다.
 
    //포맷팅합니다.
    void (*format)(struct String*const char*, ...); //포맷팅해서 그대로 대입합니다.
    void (*append_format)(struct String*const char*, ...); //포맷팅한 문자열을 이어붙입니다.
 
    //인덱싱합니다. 범위를 벗어나면 EOF를 줘요.
    int (*at)(const struct String*, size_t); //그냥 그 문자를 반환합니다.
    int* (*ptr_at)(struct String*, size_t); //그 문자의 주소를 반환합니다.
 
    //문자나 문자열을 탐색해서 인덱스를 줍니다.
    //못찾으면 EOF를 반환합니다.
    int (*findc)(const struct String*char c); //문자를 찾습니다.
    int (*finds)(const struct String*const struct String*); //String 문자열을 찾습니다.
    int (*finds_raw)(const struct String*const char*); //생 문자열을 받아서 찾습니다.
};
typedef struct String String;
typedef String string;
 
 
/*빌더 함수 선언*/
String make_string(const char*);
String make_nullstring();
 
/*String 유사메서드*/
void _string_set(String*const char*);
void _string_setn(String*const char*, size_t);
const char* _string_gets(const String*);
size_t _string_get_length(const String*);
void _string_copy_from(String* self, const String* other);
String _string_clone(const String* self);
String _string_move(String* self);
void _string_append(String* self, const String* other);
void _string_append_raw(String* self, const char* other);
void _string_swap(String* self, String* other);
void _string_clear(String* self);
int _string_is_empty(const String* self);
int _string_compare(const String* self, const String* other);
int _string_compare_raw(const String* self, const char* other);
int _string_is_same(const String* self, const String* other);
int _string_is_same_raw(const String* self, const char* other);
void _string_format(String* self, const char* format,...);
void _string_append_format(String* self, const char* format, ...);
int _string_at(const String* self, size_t index);
int _string_ptr_at(String* self, size_t index);
int _string_findc(const String* self, char c);
int _string_finds(const String* self, const String* key);
int _string_finds_raw(const String* self, const char* key);
 
 
 
/*유사메서드 정의*/
void _string_set(String* self, const char* s)
{
    self->length = strlen(s);
 
    free(self->data);
    self->data = malloc(sizeof(char)*self->length +1);
 
    strncpy(self->data, s, self->length+1);
}
 
void _string_setn(String* self, const char* s, size_t len)
{
    self->length = len;
 
    free(self->data);
    self->data = malloc(sizeof(char)*self->length +1);
 
    strncpy(self->data, s, self->length +1);
}
 
const char* _string_gets(const String* self)
{
    return self->data;
}
 
size_t _string_get_length(const String* self)
{
    return self->length;
}
 
void _string_copy_from(String* self, const String* other)
{
    self->length = other->length;
 
    free(self->data);
    self->data = malloc(sizeof(char)*self->length +1);
 
    strncpy(self->data, other->data, self->length +1);
}
 
String _string_clone(const String* self)
{
    String temp = make_nullstring();
    temp.setn(&temp, self->data, self->length);
    return temp;
}
 
String _string_move(String* self)
{
    String temp = make_nullstring();
    temp.data = self->data;
    temp.length = self->length;
 
    self->data=NULL;
    self->length=0;
 
    return temp;
}
 
void _string_append(String* self, const String* other)
{
    self->length+=other->length;
    realloc(self->data, self->length+1);
    strncat(self->data, other->data, self->length+1);
}
 
void _string_append_raw(String* self, const char* other)
{
    self->length+=strlen(other);
    realloc(self->data, self->length);
    strncat(self->data, other, self->length+1);
}
 
void _string_swap(String* self, String* other)
{
    char* t = self->data;
    size_t t2 = self->length;
 
    self->data = other->data;
    self->length = other->length;
 
    other->data = t;
    other->length = t2;
}
 
void _string_clear(String* self)
{
    self->length=0;
    free(self->data);
    self->data=NULL;
}
 
int _string_is_empty(const String* self)
{
    return self->data==NULL;
}
 
int _string_compare(const String* self, const String* other)
{
    return strcmp(self->data, other->data);
}
int _string_compare_raw(const String* self, const char* other)
{
    return strcmp(self->data, other);
}
 
int _string_is_same(const String* self, const String* other)
{
    return strcmp(self->data, other->data)==0;
}
int _string_is_same_raw(const String* self, const char* other)
{
    return strcmp(self->data, other)==0;
}
 
 
enum
{
    STRING_BUFFER_SIZE = 200 //포맷팅 함수에서 사용할 버퍼 크기. 늘려도 됨
};
 
void _string_format(String* self, const char* format,...)
{
    char buffer[STRING_BUFFER_SIZE];
 
    va_list args;
    va_start(args, format);
 
    vsprintf(buffer, format, args);
 
    self->set(&self, buffer);
 
    va_end(args);
}
 
void _string_append_format(String* self, const char* format, ...)
{
    char buffer[STRING_BUFFER_SIZE];
 
    va_list args;
    va_start(args, format);
 
    vsprintf(buffer, format, args);
 
    self->append_raw(&self, buffer);
 
    va_end(args);
}
 
int _string_at(const String* self, size_t index)
{
    if(index<0 || index>=self->length)
        return EOF;
    else
        return self->data[index];
}
 
int _string_ptr_at(String* self, size_t index)
{
    if(index<0 || index>=self->length)
        return EOF;
    else
        return &(self->data[index]);
}
 
int _string_findc(const String* self, char c)
{
    for(int i=0; i<self->length; ++i)
    {
        if(self->data[i]==c)
            return i;
    }
 
    return EOF;
}
 
int _string_finds(const String* self, const String* key)
{
    const char* finded = strstr(self->data, key->data);
    if(finded==NULL)
        return EOF;
    else
        return (int)finded - (int)(self->data);
}
 
int _string_finds_raw(const String* self, const char* key)
{
    const char* finded = strstr(self->data, key);
    if(finded==NULL)
        return EOF;
    else
        return (int)finded - (int)(self->data);
}
 
 
 
//String 유사클래스 유사객체를 생성해서 반환합니다.
String make_string(const char* s)
{
    String temp = NullString;
    temp.set(&temp, s);
    return temp;
}
 
//빈 유사객체를 생성해서 반환합니다.
String make_nullstring()
{
    String temp = NullString;
    return temp;
}
 
 
const int main(void)
{
    string s = make_string("hello");
 
    printf(s.data);
 
    return 0;
}
cs


설정

트랙백

댓글

[C] Q: 스택의 사이즈는 왜이렇게 작나요?

언어/C 2018. 12. 30. 21:10

Q: When you allocate memory on the heap, the only limit is free RAM (or virtual memory). 
힙에 메모리를 할당할 때는 램이나 가상메모리의 크기 내에서는 자유롭게 사이즈를 줄 수 있죠.

It makes Gb of memory.
그래서 보통 기가바이트 단위도 쓸 수가 있어요.


So why is stack size so limited (around 1 Mb) ? 
그런데 스택은 왜이렇게 작은거죠? 보통 1메가정도밖에 안되더라고요.

What technical reason prevents you to create really big objects on the stack ?
기술적인 이유 때문에 스택에 큰 객체를 두지 못하는건가요?

...



A: My intuition is the following. 
내 생각엔 이래요.

The stack is not as easy to manage as the heap. 
스택은 힙처럼 관리하기가 쉽지 않아요.

The stack need to be stored in continuous memory locations. 
스택은 연속적인 메모리 위치에 저장될 필요가 있거든요.

This means that you cannot randomly allocate the stack as needed, but you need to at least reserve virtual addresses for that purpose. 
스택에는 필요에 따라 랜덤으로 할당을 할수 없단거죠.
하지만 최소한 가상 주소는 예약을 해놔야 합니다.

The larger the size of the reserved virtual address space, the fewer threads you can create.
예약된 가상 주소 공간이 커질수록 만들수 있는 스레드 수는 적어져요.


For example, a 32-bit application generally has a virtual address space of 2GB. 
예를 들어 32비트 앱은 보통 2기가의 가상주소 공간을 가집니다.

This means that if the stack size is 2MB (as default in pthreads), then you can create a maximum of 1024 threads. 
그러니까 스택의 크기가 2메가면 최대 1024개의 스레드를 생성할 수가 있는거죠.

This can be small for applications such as web servers. 
웹서버 같은 앱들은 이게 적어도 되는데요.

Increasing the stack size to, say, 100MB (i.e., you reserve 100MB, but do not necessarily allocated 100MB to the stack immediately), would limit the number of threads to about 20, which can be limiting even for simple GUI applications.
스택의 크기를 100으로 늘리면(100메가를 예약해도 바로 100메가를 할당하진 않음), 스레드 수를 20개 정도로 제한할 수 있죠. 이건 간단한 gui 앱에서도 제한이 될수 있어요.


A interesting question is, why do we still have this limit on 64-bit platforms. 
흥미로운 문제는, 64비트 플랫폼에서도 여전히 이 제한이 존재한다는 거에요.

I do not know the answer, but I assume that people are already used to some "stack best practices": 
이 문제에 대해서는 답을 드리진 못하겠지만, 아마 사람들이 스택의 그 "무난한 관행"에 익숙해졌기 때문인것 같네요.

be careful to allocate huge objects on the heap and, if needed, manually increase the stack size. 
큰 객체는 힙에 놓고 필요할 때만 스택의 크기를 늘리는게 좋다는 겁니다.

Therefore, nobody found it useful to add "huge" stack support on 64-bit platforms.
그래서 64비트 플랫폼에서 어떤 환경도 기본으로 "큰" 스택을 지원하지 않는거에요.


설정

트랙백

댓글

[C] ()와 (void)의 차이

언어/C 2018. 12. 30. 21:09

C에서는 어떤 경우에도 우직하게, 위에서 아래로만 인식을 합니다.

그래서 위에서 아래에 있는 함수를 갖다 쓰려면 애가 찾질 못하죠.

그래서 전방선언-프로토타입이란걸 위에다 붙여줍니다. 보통 헤더에 분리해서 넣어주죠.

이렇게요.


자 근데. 선언부의 파라미터를 전부 지우면 어떨까요?
시그너처가 다르니 에러가 날까요?

한번 봅시다.

잘 됩니다. 

선언부에서의 빈 ()는 이건 뭐든 들어갈수 있어! 라는 뜻이기 때문이죠.

"이건 파라미터를 안 받아!"라는 의미를 부여하려면 void를 명시해줍니다.

이제 (void)라고 확실히 명시가 됐으니, 아래에 있는 정의부와 일치하지 않아서 에러가 납니다.



설정

트랙백

댓글

[C] Q: scanf에서 오류가 나요. in Visual Studio

언어/C 2018. 12. 30. 21:05

일단 이건 비주얼 스튜디오에서만 해당되는 문제입니다.


입력을 받는 간단한 프로그램을 하나 짜보도록 하죠.


1
2
3
4
5
6
7
8
9
10
11
12
#include "stdafx.h"
 
#include <iostream>
 
int main()
{
    char buffer[100];
 
    printf("암거나 입력하세요 : ");
    scanf("%s", buffer);
    printf("결과 %s", buffer);
}
cs



VS에서는 이렇게 문법적으로 아무런 문제도 없는 코드를 짜도, 문제가 발생할 수 있습니다.

초심자들이 한번씩은 걸려드는 함정이죠.


자 오류가 떴습니다. 근데 대체 뭐라고 하는걸까요?

scanf 함수는 안전하지 않으니까 scanf_s를 쓰라고 하는 겁니다.


근데 그건 니들 생각이고, 나는 그걸 쓰고싶지 않아요. 




1.define(안됐는데 알고보니 됨)

어쨌든 scanf를 쓰고싶으면 _CRT_SECURE_NO_WARNINGS라는 매크로를 정의하라고 하는데요. 그럼 이렇게 짜면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
#include "stdafx.h"
 
#include <iostream>
#define _CRT_SECURE_NO_WARNINGS //잔소리좀 하지 말
 
int main()
{
    char buffer[100];
 
    printf("암거나 입력하세요 : ");
    scanf("%s", buffer);
    printf("결과 %s", buffer);
}
cs

컴파일을 해볼까요?



이런 빌어먹을. 그래도 안된다고 합니다. 얘들이 왜이러지? 예전에는 이러면 됐었는데 뭔가 바뀌었나봅니다.


수정) 알고보니 define을 맨 위에 둬야한다네요. 잘못 씀.



2.pragma

다른 매크로를 써보죠, pragma란 것도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "stdafx.h"
 
#include <iostream>
 
#pragma warning(disable:4996//좀 닥쳐봐
 
int main()
{
    char buffer[100];
 
    printf("암거나 입력하세요 : ");
    scanf("%s", buffer);
    printf("결과 %s", buffer);
}
cs

다시 컴파일


오! 이번에는 다행히 됩니다.



3.그냥 scanf_s를 쓸까?

근데 저놈들은 이게ㅔ 뭐라고 자꾸 쓰라고 강요를 하는 걸까요?

실제로 scanf에 취약점이 존재하기 때문입니다. 전달받은 변수보다 입력으로 들어오는 값이 더 크면 버퍼오버플로가 발생하는데, 이게 상당히 위험할 수 있거든요.

그래서 더 큰 값이 들어와도 잘라버릴 수 있도록 맨 마지막 인자로 변수의 크기를 넣어줍니다. '너무 커도 이 변수 크기까지만 넣어라!' 라는 뜻이죠. 


이렇게요.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "stdafx.h"
 
#include <iostream>
 
int main()
{
    char buffer[100];
 
    printf("암거나 입력하세요 : ");
    scanf_s("%s", buffer, sizeof(buffer)); //이제 됐냐?
    printf("결과 %s", buffer);
}
 
cs


잘 됩니다.


근데 사실 _s는 그렇게 좋은 기능만은 아닙니다. 이걸 이렇게 강력하게 지원하는 컴파일러가 사실상 이거밖에 없는데요... 

굳이 이걸 쓰지 않아도 취약점을 막을 수 있는 방법이 많기 때문입니다.. 마지막 인자 때문에 추가되는 오버헤드도 있고요.




4.프로젝트 설정

코드에 손을 대고 싶지 않다면, 좀더 근본적으로 문제를 차단할 수도 있습니다.

자꾸 _s 버전 쓰라고 강요하는걸 SDL 체크라고 하는데요. 이걸 꺼버리면 됩니다.


솔루션 탐색기 창에서 프로젝트 파일에 마우스 오른쪽 버튼을 누르고

속성 창으로 들어갑니다.


그리고 C/C++ -> 일반 -> SDL 검사에서 '아니요'를 선택해주시고 확인 누르시면


잘 됩니다.

설정

트랙백

댓글

[C] C99~C11 조금 낯선 기능들

언어/C 2018. 12. 30. 20:53

구조체 리터럴 (C99)

변수명 없이 임시적으로 생성되는 구조체 리터럴을 선언할 수 있다.

(struct 구조체명) { 요소들...}


구조체 지정 초기화 (C99)

멤버를 직접 지정해서 초기화한다.
보다 명시적이고, 순서와 관련없이 대입해 넣을 수 있다.

여기엔 두가지 방법이 있는데, 
.과 =을 쓰는 방법이 이것이다.

= { .멤버명 = 대입값, ...};




근데 매번 .을 붙이려면 그것도 꽤 귀찮지 싶다.
그런 이들을 위한 두번째 방법이 있다.

= {멤버명 : 대입값, ...};



Flexible 배열 멤버 (C99)

아래와 같이 길이가 정해지지 않은 구조체 멤버 배열을 사용하는 기능이다.

struct flex_t{
    int age;
    char name[];
};

여기에는 몇가지 주의사항과 제약사항이 있다.
사실 좀 많이 까다롭다.
일단 위처럼 플렉서블 배열은 맨 뒤에 와야 한다.
그리고 다른 멤버가 하나 이상 있어야 한다.

일반적인 방법으로 사용하지도 못한다. 길이가 없기 때문에 메모리에 그를 위한 공간이 할당되지 않기 때문이다. 
위에서 사용한 구조체 리터럴 예제에 플렉서블을 사용하면 에러가 난다.

그럼 어떻게 써야할까?


결국 동적으로 할당해서 써야한다..

게다가 배열의 추가용량까지 써줘야 한다. 이렇게.



그리고 배열의 특성 중 하나인 '길이' 도 없다.


체크불가.


도대체 왜 넣은 기능인지 모르겠다. 
불편하기만 하고 쓸모없다.



익명 구조체 (C11)

구조체 안에다가 이름없는 구조체를 사용할 수 있는 기능이다.

내부의 익명 구조체 멤버는 외부의 구조체 멤버와 같이 액세스를 할 수 있다.

사실 이건 별로 쓸모가 없다. 그냥 중괄호 빼고 합쳐버리지.

어쨌든 이렇게 쓸 수 있다.



익명 공용체 (C11)

익명 공용체는 익명 구조체와 동작방식이 유사하다. 하지만 더 쓸모가 있다.

가끔 비트나 메모리 갖고 장난치다보면 구조체에 공용체를 멤버로 집어넣을 때가 있는데, 
이러면 접근시 공용체의 이름까지 써야 하기 때문에 호출하기가 굉장히 귀찮아진다.

그럴때 이걸 사용하면 번거로움을 줄일 수 있다.




__Noreturn (C11)

함수가 반환하지 않고 종료가 됨을 명시한다.

대표적으로 프로그램을 종료하는 exit함수가 이것으로 수식을 하고 있다.

근데 뭐 직접 쓸 일은 별로 없을 것 같다.





_Static_assert (C11)

c++의 static_assert와 동일하다.

컴파일타임에 assert를 뱉는다.

첫번째 인자는 논리식을 받아서 참이면 수행하고, 거짓이면 컴파일을 중단하고 두번째 인자의 문자열을 뱉는다.

성공



실패



이중자/삼중자 (C99)

어떤 키보드는 C에서 필수적으로 사용되는 기호들을 제공하지 않기도 한다.

그래서 흔한 기호를 2~3개의 기호를 조합해서 대체할 수 있게끔 이중자와 삼중자라는 것을 제공한다.

삼중자는 ""보다 우선순위가 높지만 이중자는 그렇지 않다.

# => 삼중자: ??=    이중자: %:

[  => 삼중자: ??(     이중자: <:

]  => 삼중자: ??)     이중자: :>

{  => 삼중자: ??<    이중자: <%

}  => 삼중자: ??>    이중자: %>

\  => 삼중자: ??/

|   => 삼중자: ??!

^  => 삼중자: ??`

~ => 삼중자: ??-


인라인 함수 (C99)

키워드는 inline이고 사용방법은 c++과 동일하다.




2018. 8. 31.



설정

트랙백

댓글

[C] Q: 프로그램이 실행되자마자 꺼져요!

언어/C 2018. 12. 30. 20:43

가장 흔한 질문 중 하나인데, 원래 콘솔에서는 할일 다하면 바로 꺼지는 게 맞는 겁니다.

게다가 요즘 컴퓨터는 겁나게 빠르기 때문에 텍스트 처리 정도의 가벼운 작업 정도는 쉬시식 끝내버리죠. 그래서 그냥은 볼 새가 없습니다.

해결법 1 : Visual Studio를 사용중이라면 컨트롤+F5로 실행합니다. 그럼 꺼지지 않습니다.
Clion 같이 자체 콘솔을 내장하는 IDE를 사용하는 것도 좋습니다.

해결법 2 : windows.h헤더의 system함수로, 코드 마지막 부분, return 앞에 system("pause"); 라고 써줍니다. 
pause는 좀 멈춰있으라는 커맨드 명령어입니다.

해결법 3: 사실 방법은 많습니다. 그냥 꺼지지 않게만 하면 되기 때문에, return 앞 끝부분에다 비어있는 무한루프를 붙여도 되고, 의미없는 입력함수를 넣어도 됩니다..
이중에 제일 간단한건 getchar(); 입니다.




2018. 8. 27

설정

트랙백

댓글

[C] 함수 호출 규약.link

언어/C 2018. 12. 17. 11:45

함수 호출 규약(Function calling convention)
함수 시그너처에서, 리턴타입과 함수명 사이에 붙어서 함수의 작동 방식을 결정하는 것.
사실 대부분의 경우에서는 직접 명시할 필요가 별로 없음

https://ko.m.wikipedia.org/wiki/X86_호출_규약
위키피디아


http://sweeper.egloos.com/m/829514
친절함


http://qufl1999.egloos.com/m/2338204



http://blog.eairship.kr/m/254




결론.

stdcall
대부분의 경우에는 __stdcall이 약간 더 가볍고 빠름.
다른 별칭으로 CALLBACK, WINAPI, PASCAL, APIENTRY 등이 있음
가변인자 사용 불가

cdecl
가변인자를 사용하려면 __cdecl 사용 필요.
다른 별칭으로 WINAPIV 등이 있음
함수 디폴트 설정임

'언어 > C' 카테고리의 다른 글

[C] C99~C11 조금 낯선 기능들  (0) 2018.12.30
[C] Q: 프로그램이 실행되자마자 꺼져요!  (0) 2018.12.30
[C] 쇼트 서킷으로 조건문 구현  (0) 2018.12.17
[C] sizeof 연산자에 대해서  (0) 2018.12.17
[C] 포인터란?  (0) 2018.12.17

설정

트랙백

댓글

[C] 쇼트 서킷으로 조건문 구현

언어/C 2018. 12. 17. 06:30

보통 조건문을 사용할땐 if 키워드를 사용하곤 한다.

너무 진부하지 않은가?

스위치도 있지만 경우가 좀 다르고

삼항연산자도 나쁘지 않지만 더 세련된 조건문의 대체재가 있다.

바로 쇼트서킷이라 하는 최적화 현상을 이용하는 것이다.

이게 뭐냐면, 가령 && 연산을 한다 쳐보자. 
이 연산은 양쪽이 전부 true일 경우에만 true를 반환한다. 
그 말인즉 하나라도 false면 무조건 false가 된다는 말이고, &&연산의 앞부분이 false로 판명나면 뒷부분을 무시하고 지나가도록 최적화를 한다.
이게 바로 쇼트서킷이다.

그리고 ||도 마찬가지다. 앞부분이 true면 그냥 넘어간다.

이 현상을 이용해서 우린 더 멋진 분기를 구성해볼수 있다.

이런 식으로





'언어 > C' 카테고리의 다른 글

[C] Q: 프로그램이 실행되자마자 꺼져요!  (0) 2018.12.30
[C] 함수 호출 규약.link  (0) 2018.12.17
[C] sizeof 연산자에 대해서  (0) 2018.12.17
[C] 포인터란?  (0) 2018.12.17
[C] C언어 유니코드 사용법  (0) 2018.12.17

설정

트랙백

댓글