Cfaqs Ko
Cfaqs Ko
모든 C 프로그래머들에게 이 책을 바칩니다.
Contents
1.5 Typedefs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.10 Namespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.11 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.6 Unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.7 Enumerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.8 Bitfields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2
CONTENTS 3
3 Expressions 59
4 Pointer 73
5 Null Pointers 84
5.3 Retrospective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
10 C Preprocessor 150
11.12Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
17 Style 294
20 Miscellaneous 328
21 Extensions 346
Original Preface
At some point in 1979, I heard a lot of people talking about this relatively
new language, C, and the book that had just come out about it. I bought a
copy of K&R, otherwise known as The C Programming Language, by Brian
Kernighan and Dennis Ritchie, but it sat on my shelf for a while because I
didn’t have an immediate need for it (besides which I was busy being a college
freshman at the time.) It proved in the end to be an auspicious purchase,
though, because when I finally did take it up, I never put it down: I’ve been
programming in C ever since.
In 1983, I came across the Usenet newsgroup net.lang.c, which was (and its
successor comp.lang.c still is) an excellent place to learn a lot more about C,
to find out what questions everyone else is having about C, and to discover
that you may not know all there is to know about C after all. It seems that
C, despite its apparent simplicity, has a number of decidedly nonobvious as-
pects, and certain questions come up over and over again. This book is a
collection of some of those questions, with answers, based on the Frequently
Asked Questions (“FAQ”) list I began posting to comp.lang.c in May 1990.
I would never have learned enough about C to be able to write this book,
7
CONTENTS 8
and I would not be attempting to make C more pleasant for others to use by
writing this book now, if I did not think that C is a great language or if I
did not enjoy programming in it. I do like C, and one of the reasons I teach
classes in it and spend time participating in discussion about in on the Inter-
net is that I would like to discover which aspects of C (or of programming in
general) are difficult to learn or keep people from being able to program effi-
ciently and effectively. This book represents some of what I’ve learned: These
questions are certainly some of the ones people have the most trouble with,
and the answers have been refined over several years in an attempt to ensure
that people don’t have too much trouble with them.
A reader will certainly have trouble if there are any errors in these answers,
and although the reviewers and I have worked hard to eliminate them, it can
be as difficult to eradicate the last error from a large manuscript as it is to
stamp out the last bug in a program. I will appreciate any corrections or
suggestions sent to me in care of the publisher or at the e-mail address given,
and I would like to offer the customary $1.00 reward to the first finder of any
error. If you have access to the Internet, you can check for an errata list (and
a scorecard of the finders) at the ftp and http addresses mentioned in question
20.40.
As I hope I’ve made clear, this book is not a critique of the C programming
langauge, nor is it a critique of the book from which I first learned C or of
that book’s authors. I didn’t just learn C from K&R; I also learned a lot of
programming. As I contemplate my own contribution to the C programming
literature, my only regret is that the present book does not live up to a nice
observation made in the second edition of K&R, namely, that “C is not a big
language, and it is not well served by a big book.” I hope that those who
most deeply appreciate C’s brevity and precision (and that of K&R) will not
be too offended by the fact that this book says some things over and over and
over or in three slightly different ways.
Although my name is on the cover, there are a lot of people behind this book,
and it’s difficult to know where to start handling out acknowledgements. In
a sense, every one of comp.lang.c’s readers (today estimated at 320,000) is a
contributor: The FAQ list behind this book was written for comp.lang.c first,
and this book retains the flavor of a good comp.lang.c discussion.
This book also retains, I hope, the philosophy of correct C programming that
I began learning when I started reading net.lang.c. Therefore, I shall first ac-
CONTENTS 9
knowledge the posters who stand out in my mind as having most clearly and
consistently articulated that philosophy: Doug Gwyn, Guy Harris, Karl Heuer,
Henry Spencer, and Chris Torek. These gentlemen have displayed remarkable
patience over the years, answering endless questions with generocity and wis-
dom. I was the one who stuct his neck out and started writing the Frequent
questions down, but I would hate to give the impression that the answers are
somehow mine. I was once the student (I believe it was Guy who answered
my posting asking essentially the present volume’s question 5.10), and I owe
a real debt to the masters who went before me. This book is theirs as much
as mine, though I retain title to any inadequacies or mistakes I’ve made in
the presentation.
The former on-line FAQ list grew by a factor of three in the process of be-
coming this book, and its growth was a bit rapid and awkward at times. Mark
Brader, Vinit Carpenter, Stephen Clamage, Jutta Degener, Doug Gwyn, Karl
Heuer, Joseph Kent, and George Leach read proposals or complete drafts and
helped to exert some control over the process; I thank them for their many
careful suggestions and corrections. Their efforts grew out of a shared wish
to improve the overall understanding of C in the programming community. I
appreciate their dedication.
Three of those reviewers have also been long-time contributors to the on-
line FAQ list. I thank Jutta Degener and Karl Heuer for their help over the
years, and I especially thank Mark Brader, who has been my most persistent
critic ever since I first began posting the comp.lang.c FAQ list five years ago.
I don’t know how he has had the stamina to make as many suggestions and
corrections as he has and to overcome my continuing stubborn refusal to agree
with some of them, even though (as I eventually understood) they really were
improvements. You can thank Mark for the form of many of this book’s ex-
planations and blame me for mangling any of them.
Additional assorted thanks: to Susan Cyr for the cover art; to Bob Dinse and
Eskimo North for providing the network access that is particularly vital to a
project like this; to Bob Holland for providing the computer on which I’ve
done most of the writing; to Pete Keleher for the Alpha text editor; to the
University of Washington Mathematics Research and Engineering libraries for
access to their collections; and to the University of Washington Oceanoraphy
department for letting me borrow their tape drivers to access my dusty old
archives of Usenet postings.
CONTENTS 10
Thanks to all these people, all over the world, who have contributed to the
FAQ list in various ways by offering suggestions, corrections, constructive crit-
icism, or other support: Jamshid Afshar, David Anderson, Tanner Andrews,
Sudheer Apte, Joseph Arceneaux, Randall Atkinson, Rick Beem, Peter Ben-
nett, Wayne Berke, Dan Bernstein, John Bickers, Gary Blaine, Yuan Bo, Dave
Boutcher, Michael Bresnahan, Vincent Broman, Stan Brown, Joe Buehler, Kim-
berley Burchett, Gordon Burditt, Burkhard Burow, Conor P. Cahill, D’Arcy
J.M. Cain, Christopher Calabrese, Ian Cargill, Paul Carter, Mike Chambers,
Billy Chambless, Franklin Chen, Jonathan Chen, Raymond Chen, Richard
Cheung, Ken Corbin, Ian Cottam, Russ Cox, Jonathan Coxhead, Lee Craw-
ford, Steve Dahmer, Andrew Daviel, James Davies, John E. Davis, Ken De-
long, Norm Diamond, Jeff Dunlop, Ray Dunn, Stephen M. Dunn, Michael
J. Eager, Scott Ehrlich, Arno Eigenwillig, Dave Eisen, Bjorn Engsig, David
Evans, Clive D.W. Feather, Dominic Feeley, Simao Ferraz, Chris Flatters, Rod
Flores, Alexander Forst, Steve Fosdick, Jeff Francis, Tom Gambill, Dave Gille-
spie, Samuel Goldstein, Tim Goodwin, Alasdair Grant, Ron Guilmette, ... I
have tried to keep track of everyone whose suggestions I have used, but I fear
I’ve probably overlooked a few; my apologies to anyone whose name should
be on this list but isn’t.
Seattle, Washington
July, 1995
Steve Summit
[email protected]
될 수는 없습니다.
http://www.eskimo.com/~scs/C-faq/top.html
http://www.faqs.org/faqs/
1. 선언과 초기화
3. 식 (Expressions)
4. 포인터
5. 널 (null) 포인터
6. 배열과 포인터
7. 메모리 할당 (allocation)
8. 문자와 문자열
9. Boolean 식과 변수
13. 라이브러리 함수
CONTENTS 13
17. 스타일
18. 툴과 기타 자료
20. 기타 (miscellaneous)
21. 참고문헌
22. Acknowledgements
About Translation
cinsky at gmail.com
http://www.cinsk.org/cfaqs/
Translation
http://www.cinsk.org/cfaqs/
Acknowledgements
Declarations and
Initializations
16
CHAPTER 1. DECLARATIONS AND INITIALIZATIONS 17
이 규칙은 char 가 적어도 8 bit 가 되어야 한다는 것과, short int 와 int
는 적어도 16 bit 여야 한다는 것과, long int 는 적어도 32 bit 가 되어야
한다는 것을 뜻합니다. (각각 type 의 signed 와 unsigned version 은 같은
크기를 가진다고 보장되어 있습니다.) ANSI C 에서 특정 machine 에서 각
각 type 의 최소값과 최대값은 <limits.h> 에 정의되어 있으며, 요약하면
다음과 같습니다 :
Base type Min. size Min. value Max. value Max. value
(bits) (signed) (signed) (unsigned)
char 8 -127 127 255
short 16 -32,767 32,767 65,535
int 16 -32,767 32,767 65,535
long 32 -2,147,483,647 2,147,483,647 4,294,967,295
1 sign-extension
CHAPTER 1. DECLARATIONS AND INITIALIZATIONS 18
또한, 정확한 크기를 요구하는 정수 타입을 선언하기 위해, C99 표준은 <stdint.h>
를 통해 여러 가지 정수 타입을 제공합니다. 여기에 관한 것은 11.I 를 참고
하기 바랍니다.
Note 최신 C 표준, C99 에서는 적어도 64 bit 이상인, long long 타입을 지원합
니다. 질문 1.1, 1.3 을 참고하기 바랍니다.
char *p;
*p = malloc(10);
extern int i;
int i = 0;
int f()
{
return 1;
}
DEFINE(int, i);
1.5 Typedefs
typedef struct {
char *item;
NODEPTR next;
} *NODEPTR;
struct node {
char *item;
struct node *next;
};
typedef struct node *NODEPTR;
typedef struct {
int afield;
BPTR bpointer;
} * APTR;
typedef struct {
int bfield;
APTR apointer;
} * BPTR;
struct a {
int afield;
struct b *bpointer;
};
struct b {
int bfield;
struct a *apointer;
};
struct b;
struct b {
int bfield;
APTR apointer;
};
struct x1 { ... };
typedef struct { ... };
Q 1.20 const char *p, char const *p, char * const p 가 서로 어떻게 다른가
요?
• char *(*(*a[N])())();
• typedef 를 써서 차례대로 만들어 가면 됩니다 :
file1.c:
int array[] = { 1, 2, 3 };
file2.c:
extern int array[];
CHAPTER 1. DECLARATIONS AND INITIALIZATIONS 32
file1.c:
int array[] = { 1, 2, 3};
int arraysz = sizeof(array);
file2.c:
extern int array[];
extern int arraysz;
file1.h:
#define ARRAYSZ 3
file1.c:
#include "file1.h"
int array[ARRAYSZ];
file2.c:
#include "file1.h"
extern int array[ARRAYSZ];
file1.c:
int array[] = { 1, 2, 3};
file2.c:
extern int array[];
double array[256][256];
1.10 Namespace
1.11 Initialization
int f()
{
char a[] = "hello, world!";
}
char *p = malloc(10);
struct x1 { ... };
typedef struct { ... } x2;
42
CHAPTER 2. STRUCTURES, UNIONS, AND ENUMERATIONS 43
x2 b;
struct x1 a;
struct x { ... };
x thestruct;
struct x thestruct;
tx thestruct;
언어에서는 이 두가지 방식이 차이가 없습니다. 몇몇 C++ 컴파일러는 C 와 호환을 위해
1 C++
C 언어처럼 동작합니다. C++ 에서는 구조체 tag 는 자동으로 typedef 이름으로 선언됩니다.
CHAPTER 2. STRUCTURES, UNIONS, AND ENUMERATIONS 44
struct name {
int namelen;
char namestr[1];
};
CHAPTER 2. STRUCTURES, UNIONS, AND ENUMERATIONS 45
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
struct name {
int namelen;
char namestr[MAX];
};
#include <stdlib.h>
#include <string.h>
struct name {
int namelen;
char *namep;
};
if (ret != NULL) {
ret->namelen = strlen(newname);
ret->namep = malloc(ret->namelen + 1);
if (ret->namep == NULL) {
free(ret);
return NULL;
}
strcpy(ret->namestr, newname);
}
return ret;
}
return ret;
}
Note C99 표준에 소개된, “flexible array member” 를 쓰면, 이 문제를 깔끔하게
해결할 수 있습니다. 반드시 질문 11.G 를 읽기 바랍니다.
struct {
char c;
int i;
};
offsetb = offsetof(struct a, b)
Answer The rule (see question 6.3) that causes array references to “decay” into
pointers is a special case that applies only to arrays and that reflects
their “second-class” status in C. (An analogous rule applies to func-
tions.) Structures, however, are first-class objects: When you mention
a structure, you get the entire structure.
struct list {
char *item;
struct list *next;
}
main(argc, argv)
{ ... }
2.6 Unions
struct taggedunion {
enum { UNKNOWN, INT, LONG, DOUBLE, POINTER } code;
union {
int i;
long l;
double d;
void *p;
} u;
};
2.7 Enumerations
Note 최신의 GCC 에 적절한 디버깅 옵션을 주면, 디버거 GDB 에서, 매크로도
값이 아닌, 이름 (symbol 값) 으로 보여줍니다. 따라서 이 경우, enum 이 가
지는 장점 하나는 없어진다고 말할 수 있습니다.
2.8 Bitfields
struct record {
char *name;
int refcount : 4;
unsigned dirty : 1;
};
Q 2.26 Why do people use explicit masks and bit-twiddling code so much in-
stead of declaring bitfields?
Answer Bitfields are thought to be nonportable, although they are no less portable
than other parts of the language. You don’t know how large they can
be, but that’s equally true for values of type int. You don’t know by
default whether they’re signed, but that’s equally true of type char. You
don’t know whether they’re laid out from left to right or right to left in
memory, but that’s equally true of the bytes of all types and matters
only if you’re trying to conform to externally imposed storage layout.
(Doing so is always nonportable; see also question 2.12 and 20.5.)
Bitfields are inconvenient when you also want to be able to manipulate
some collection of bits as a whole (perhaps to copy a set of flags). You
can’t have arrays of bitfields; see also question 20.8. Many programmers
suspect that the compiler won’t generate good code for bitfields; histor-
ically, this was sometimes true.
Straightforward code using bitfields is certainly clearer than the equiv-
alent explicit masking instructions; it’s too bad that bitfields can’t be
used more often.
Chapter 3
Expressions
a[i] = i++;
59
CHAPTER 3. EXPRESSIONS 60
int i = 7;
printf("%d\n", i++ * i++);
int i = 3;
i = i++;
a ^= b ^= a ^= b
이 코드가 올바른가요 ?
Answer 항상 그런 것은 아닙니다.
연산자 우선 순위와 괄호는 수식 평가의 일부분만을 변경할 수 있습니다.
다음과 같은 수식에서 :
Answer 보장합니다.
if (d != 0 && n / d > 0) {
/* average is greater than 0 */
}
이나,
if (p == NULL || *p == ’\0’) {
/* no string */
}
불가능해집니다.
CHAPTER 3. EXPRESSIONS 65
a[i] = i++;
three objects are distinct, i.e., only if two different pointers p and
q or two different array indices i and j are used.
(d) You may also break the first rules if you interpose a defined se-
quence point operator between the two modifications or between
the modification and the access. This expression (commonly seen
in a while loop while reading a line) is legal because the second
access of variable c occurs after the sequence point implied by &&.
if (a < b < c)
...
또는 다음과 같이 합니다 :
또는,
((condition) ? a : b) = complicated_expression;
a ? b = c : d
(a ? b) = (c : d)
CHAPTER 3. EXPRESSIONS 71
a ? (b = c) : d
질문 3.19 를 보기 바랍니다.
Pointer
73
CHAPTER 4. POINTER 74
char *p;
*p = malloc(10);
p = malloc(10);
*p = ’H’;
char *p = malloc(10);
((int *)p)++;
p += sizeof(int);
void f(ip)
int *ip;
{
static int dummy = 5;
ip = &dummy;
}
int *ip;
f(ip);
void f(ipp)
int *ipp;
{
static int dummy = 5;
*ipp = &dummy;
}
...
int *ip;
f(&ip);
int *f()
{
static int dummy = 5;
return &dummy;
}
double *dp;
void *vp = dp;
f(&vp);
dp = vp;
int i = 1;
double d = i;
incme(&d);
i = d;
int i = 1;
incme((double *)&i) /* WRONG */
f(&5);
int five = 5;
f(&five);
Null Pointers
For each pointer type, C defines a special pointer value, the null pointer, that
is guaranteed not to point to any object or function of that type. (The null
pointer is analogous to the nil pointer in Pascal and LISP.) C programmers
are often confused about the proper use of null pointers and about their inter-
nal representation (even though the internal representation should not matter
to most programmers). The null pointer constant used for representing null
pointers in source code involves the integer 0, and many machines represent
null pointers internally as a word with all bits zero, but the second fact is not
guaranteed by the language.
These first three questions cover the fundamental definitions of null pointers
in the language.
84
CHAPTER 5. NULL POINTERS 85
char *p = 0;
if (p != 0)
고정된 인자 함수 호출에서 가변 인자
(variable argument) 사용
if (expr)
if ((expr) != 0)
!expr
(expr) ? 0 : 1
또는 다음과 같이 쓸 수 있습니다 :
((expr) == 0)
따라서, 다음과 같이 쓰는 것은 :
if (!p)
다음과 같이 쓰는 것과 같습니다 :
if (p == 0)
So that a program’s use of null pointers can be made a bit more explicit,
a standard preprocessor macro, NULL, is defined, having as its value a null
pointer constant. Unfortunately, although it is supposed to clarify things, this
extra level of abstraction sometimes introduces extra level of confusion.
CHAPTER 5. NULL POINTERS 89
이게 좋은 습관일까요 ?
5.3 Retrospective
5 Using (void *)0, in the guise of NULL, instead of (char *)0 happens to work only because
of a special guarantee about the representations of void * and char * pointers.
CHAPTER 5. NULL POINTERS 94
only sense 4; the other usages all use “null” as an adjective, as does the (unrelated) term “null
statement.” These are admittedly fine points
CHAPTER 5. NULL POINTERS 95
union {
int *u_p;
int u_i; /* assumes sizeof(int) >= sizeof(int *) */
} p;
p.u_i = 0;
99
CHAPTER 6. ARRAYS AND POINTERS 100
a: h e l l o \0
p: h e l l o \0
arrays of wchar t.
3 Strictly speaking, the [] operator is always applied to a pointer; see question 6.10 item 2
CHAPTER 6. ARRAYS AND POINTERS 102
p = a;
6.3 Retrospective
Because the basic relationship between arrays and pointers occasionally gen-
erates so much confusion, here are a few questions about that confusion.
(a) Pointers can simulate arrays (though that’s not all; see question
4.1)
(b) There’s hardly such a thing as an array (it is, after all, a “second-
class citizen”); the subscripting operator [] is in fact a pointer op-
erator.
(c) At a higher level of abstraction, a pointer to a block of memory is
effectively the same as an array (although this says nothing about
other uses of pointers).
But to reiterate, here are two ways not to think about it:
(d) “They’re completely the same.” (False; see question 6.2.)
(e) “Arrays are constant pointers.” (False; see question 6.9.)
Since arrays usually decay into pointers, it’s particularly easy to get confused
when dealing with the occasional pointer to an entire array (as opposed to a
pointer to its first element).
int a[10];
int array[NROWS][NCOLUMNS];
int a1[3] = { 0, 1, 2 };
int a2[2][3] = { { 3, 4, 5 }, { 6, 7, 8 } };
int *ip; /* pointer to int */
int (*ap)[3]; /* pointer to array [3] of int */
ip = a1;
printf("%d ", *ip);
8 This discussion also applies to three- or more dimensional arrays.
CHAPTER 6. ARRAYS AND POINTERS 109
ip++;
printf("%d\n", *ip);
0 1
만약 a1 에 ap 를 쓰려 하면 :
ap = &a1;
printf("%d\n", **ap);
ap++; /* WRONG */
printf("%d\n", **ap); /* undefined */
ap = a2;
printf("%d %d\n", (*ap)[0], (*ap)[1]);
ap++; /* steps over entire (sub)array */
printf("%d %d\n", (*ap)[0], (*ap)[1]);
3 4
6 7
The close relationship between arrays and pointers makes it easy to use a
pointer to dynamically allocated memory to simulate an array, of size deter-
mined at run time.
CHAPTER 6. ARRAYS AND POINTERS 110
#include <stdlib.h>
int *dynarray;
dynarray = malloc(10 * sizeof(int));
#include <stdlib.h>
tive indexing
11 A macro such as #define Arrayaccess(a, i, j) ((a)[(i) * ncolumns + (j)]) could
hide the explicit calculation. Invoking that macro, however, would require parentheses and
commas that wouldn’t look exactly like conventional C multidimensional array syntax, and
the macro would need access to at least one of the dimensions, as well.
CHAPTER 6. ARRAYS AND POINTERS 112
int (*array4)[NCOLUMNS] =
(int (*)[NCOLUMNS])malloc(nrows * sizeof(*array4));
또는,
int (*array5)[NROWS][NCOLUMNS] =
(int (*)[NROWS][NCOLUMNS])malloc(sizeof(*array5));
도 가능합니다.
그러나 이런 방식은 매우 복잡한 문법을 써야 합니다. (배열 array5 에 접
근하기 위해서는 (*array5)[i][j] 와 같이 씀) 그리고 최대, 한 차원은 실
행 시간에 정해져야 합니다.
이 모든 테크닉과 함께, 이렇게 할당한 배열이 더 이상 필요없을 때에는,
free 를 써서 돌려 주어야 합니다 ; array1 과 array2 의 경우 여러 단계를
거쳐야 합니다 (질문 7.23 참고):
int realarray[10];
int *array = &realarray[-1];
References [K&R2] § 5.3 p. 100, § 5.4 pp. 102–3, § A7.7 pp. 205–6
[ANSI] § 3.3.6
[C89] § 6.3.6
[ANSI Rationale] § 3.2.2.3
int array[NROWS][NCOLUMNS];
f(array);
int array[NROWS][NCOLUMNS];
int **array1; /* ragged */
int **array2; /* contiguous */
int *array3; /* "flattened" */
int (*array4)[NCOLUMNS];
int (*array5)[NROWS][NCOLUMNS]
The sizeof operator will tell you the size of an array if it can, but it’s not
able to if the size is not known or if the array has already decayed to a pointer.
f(char a[10])
{
int i = sizeof(a);
printf("%d\n", i);
}
int array[] = { 1, 2, 3 };
int narray = sizeof(array) / sizeof(array[0]);
Memory Allocation
char *answer;
printf("Type something:\n");
gets(answer);
printf("You typed \"%s\"\n", answer);
int i;
printf("i = %d\n", i);
119
CHAPTER 7. MEMORY ALLOCATION 120
#include <stdio.h>
#include <string.h>
char *p;
strcpy(p, "abc");
char *p;
char linebuf[80];
char *lines[100];
int i;
#include <stdio.h>
char *itoa(int n)
{
char retbuf[20]; /* WRONG */
sprintf(retbuf, "%d", n);
return retbuf; /* WRONG */
}
...
char str[20];
itoa(123, str);
#include <stdlib.h>
char *itoa(int n)
{
char *retbuf = malloc(20);
if (retbuf != NULL)
sprintf(retbuf, "%d", n);
return retbuf;
}
...
#include <stdio.h>
#include <stdlib.h>
char *p;
*p = malloc(10);
Answer 256 곱하기 256 은 65,536 이며, int 가 16-bit 인 경우, 저장될 수 없는, 큰
값입니다. 게다가 이 수치는 다시 sizeof(double) 로 곱해야 하기 때문에
상당히 큰 크기입니다. 이런 큰 배열이 꼭 필요하다면 꽤 주의를 기울여야
합니다. 만약 여러분의 시스템에서 size_t 타입이 (malloc()이 인자로 받
는 타입) 32 비트라면, 그리고 int 가 16 비트라면, 위 코드에서 malloc 의
인자로 256 * (256 * sizeof(double)) 를 써서 해결할 가능성도 있습니
다. (질문 3.14 참고). 그렇지 않다면 여러분은 이 메모리를 작은 크기로
쪼개어 쓰거나, 또는 32 비트 컴퓨터나 컴파일러를 쓰거나, 비표준으로 제
공되는 메모리 할당 함수를 써야 할 것입니다. 덧붙여 질문 7.15, 19.23 도
참고하시기 바랍니다.
struct node {
struct node *next;
...
};
Memory allocated with malloc can persist as long as you need it. It is never
deallocated automatically (except when your program exits; see question 7.24).
When your program uses memory on a transient basis, it can—and should—
recycle it by calling free.
nextp = listp->next;
free(listp);
}
Q 7.29 (질문 6.14 를 따라서) 배열을 동적으로 할당한 다음, 이 배열의 크기를 바꿀
수 있을까요 ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
p = malloc(10);
strcpy(p, "Hello,"); /* p is a string */
p2 = strchr(p, ’,’); /* p2 points into that string */
tmpoffset = p2 - p;
newp = realloc(p, 20);
if (newp != NULL) {
p = newp; /* p may have moved */
p2 = p + tmpoffset; /* relocate p2 as well */
strcpy(p2, ", world");
}
printf("%s\n", p);
3 또는항상 크기를 줄이는데에만 쓰이는 것도 아닙니다.
4 그러나 어떤, ANSI 이전의 컴파일러에서는 realloc 이 실패했을 경우, 인자로 전달되었던 메모
리 블럭의 보존 여부를 보장하지 않습니다.
CHAPTER 7. MEMORY ALLOCATION 137
p = malloc(m * n);
memset(p, 0, m * n);
See also question 13.1 through 13.7, which cover library functions for string
handling.
strcat(string, ’!’);
139
CHAPTER 8. CHARACTERS AND STRINGS 140
strcat(string, "!");
char *string;
...
if (string == "value") {
/* string matches "value" */
...
}
if (strcmp(string, "value") == 0) {
/* string matches "value" */
...
}
CHAPTER 8. CHARACTERS AND STRINGS 141
왜 이렇게는 할 수 없을까요 ?
char a[14];
a = "Hello, world!";
A 65 A 65
Q 8.8 사용자가 입력한 문자열을 읽어서 배열에 저장한 다음, 나중에 출력하려고
합니다. 사용자가 \n 와 같은 문자를 입력한 경우, 왜 제대로 처리되지 않
을까요 ?
Q 8.10 I’m starting to think about multinational character sets. Should I worry
about the implication of making sizeof(char) be 2 so that 16-bit char-
acter sets can be represented?
C provides no formal, built-in Boolean type. Boolean values are just integers
(though with greatly reduced range!), so they can be held in any integral type.
C interprets a zero value as “false” and any nonzero value as “true.” The
relational and logical operators, such as ==, !=, <, >=, &&, and ||, return the
value 1 for “true,” so 1 is slightly more distinguished as a truth value than
the other nonzero values (but see question 9.2).
144
CHAPTER 9. BOOLEAN EXPRESSIONS AND VARIABLES 145
또는
또는
#include <stdbool.h>
_Bool a; /* okay */
bool b; /* okay, using macro ‘bool’ */
References [C89] § 6.2.5 p. 33, § 6.3.1.2 p. 43, § 6.5.8 p. 86, § 6.5.9 p. 86 § 7.16
p. 252
[H&S2002] § 5.1.2 p. 128, § 5.1.5 p. 132 § 7.6.4 p. 233
if ((a == b) == TRUE)
if (a == b)
if ((a == b) == TRUE)
왜 다음과 같이 쓰지 않나요 ?
#include <ctype.h>
...
if (isupper(c)) {
...
}
if (isvegetable == TRUE)
또는,
if (fileexists(outfile) == YES)
C Preprocessor
The first part of this chapter is arranged around the major preprocessor di-
rectives: #define (questions 10.1 through 10.5), #include (questions 10.6 through
10.11), and #if (questions 10.12 through 10.19). Questions 10.20 through 10.25
cover fancier macro replacement, and finally questions 10.26 and 10.27 cover
a particular set of problems relating to the preprocessor’s lack of support for
variable-length macro argument lists.
#define square(x) x * x
150
CHAPTER 10. C PREPROCESSOR 151
i / square(n)
i / n * n
i / (n * n)
square(n + 1)
n + 1 * n + 1
(n + 1) * (n + 1)
square(i++)
i++ * i++
#define begin {
#define end }
MACRO(arg1, arg2);
if (cond)
MACRO(arg1, arg2);
else /* some other code */
if (cond)
{ stmt1; stmt2; };
else /* some other code */
#define MULTI_STATEMNT_MACRO(x) do { \
stmt1; \
stmt2; \
} while(0);
if (some_condition)
MULTI_STATEMNT_MACRO(a);
else {
/* ... */
}
3 “dead” test
4 branches on the constant condition 0
CHAPTER 10. C PREPROCESSOR 156
References
• 매크로 정의 (#define)
• structure, union, enum 선언
• typedef 선언
• 외부 (external) 함수 선언 (질문 1.11 참고)
• 전역 (global) 변수 선언
#ifndef HFILENAME_USED
#define HFILENAME_USED
...header file contents...
#endif
file1.h:
#include TRUE 1
...
file2.h:
#include TRUE 1
...
#ifndef TRUE
#define TRUE 1
#endif
#define RED 1
#define BLUE 2
#define GREEN 3
#define RED 1
#define BLUE 2
#define GREEN 3
#endif
http://www.gnu.org/software/autoconf/
ftp://ftp.gnu.org/pub/gnu/autoconf/
#define a b \
#ifdef whatever
c d
#else
e f g
#endif
CHAPTER 10. C PREPROCESSOR 163
#ifdef whatever
#define a b c d
#else
#define a b e f g
#endif
#define XPaste(s) s
#define Paste(a, b) XPaste(a)b
tchars.t_eofc = CTRL(D);
CTRL(’D’)
또는
There are sometimes good reasons for a function to accept a variable number
of arguments (the canonical example is printf; see also Chapter 15). For the
same sorts of reasons, it’s sometimes wished that a function-like macro could
accept a variable number of arguments; a particularly common wish is for a
way to write a general-purpose printf-like DEBUG() macro.
DEBUG("i = %d" _ i)
또는,
또는,
References
#include <stdio.h>
#include <stdarg.h>
다음과 같이 확장됩니다 :
ANSI/ISO Standard C
174
CHAPTER 11. ANSI/ISO STANDARD C 175
있도록 합니다.
또는 다음 주소도 가능합니다 :
ISO Sales
Case Postale 56
CH-1211 Geneve 20
Switzerland
http://www.lysator.liu.se/c/schildt.html
http://www.dkuung.dk/JTC1/SC22/WG14/
Note 최신 C 표준인 C99 의 PDF 버전 (ISO web site 에서) 공식 가격은 (2005 년
1 월 24 일자로) 340 CHF 입니다. 이 날짜로, 원화 가격은 약 30 만원입니다.
ANSI 를 비롯, 다른 web site 에서도 판매하고 있습니다. 구입할 때, 무료로
배포된는 Corrigenda (버그 수정) 문서도 꼭 함께 받으시기 바랍니다. 현재
다음 두 가지가 나와 있습니다 :
http://www.lysator.liu.se/c/index.html
http://www.dkuug.dk/JTC1/SC22/WG14/
http://www.dmk.com/
Note http://www.dkuug.dk/JTC1/SC22/WG14/
위 사이트의 새 주소는 다음과 같습니다 :
http://www.open-std.org/jtc1/sc22/wg14/
int func(x)
float x;
{ ...
struct x;
printf("%d", n);
const int n = 5;
int a[n];
const charp p;
int main(void);
int main(int argc, char *argv[]);
int main()
Q 11.12b “main returns no value” 라는 경고를 피하기 위해, main()을 void 타입으
로 선언해도 괜찮을까요 ?
#include <unistd.h>
니다.
CHAPTER 11. ANSI/ISO STANDARD C 192
ANSI C introduces a few new features into the C preprocessor, including the
“stringizing” and “token pasting” operators and the #pragma directive.
#define Str(x) #x
#define Xstr(x) Str(x)
#define OP plus
char *opname = Xstr(OP);
TRACE(i, %d);
int a[3] = { 1, 2, 3 };
int b[3] = { 0, 9, 8 };
int *c[2] = { a, b };
...
Answer 아마도 C99 표준을 지원하지 못하는 (ANSI 표준만을 지원하는) 컴파일러
를 쓰신 것 같습니다. ANSI 표준, 즉 C89 표준에 따르면 초기화에 쓸 수
있는 수식에 다음과 같은 제한이 있습니다 :
11.8 Compliance
Obviously, the whole point of having a standard is so that programs and com-
pilers can be compatible with it (and therefore with each other). Compatibil-
ity is not a simple black-or-white issue, however: There are degrees of com-
pliance, and the scope of the standard’s definitions is not always as compre-
hensive as might be expected. In keeping with the “spirit of C,” several issues
are not precisely specified; portable programs must simple avoid depending on
these issues.
References [H&S2002] § 4.4.5 [C99 Rationale] § 5.1.2.3, § 5.2.3, § 6.7.3 [C99] § 5.1.2.3,
§ 6.7.3 pp. 108–109,
§ 7.13.2.1, § 7.14
The type qualifier restrict is new in C99. It may only be used to qualify
pointers to object or incomplete types, and in serves as a “no alias” hint to
the C compiler...
Q 11.G C99 에 “flexible array member” 가 소개된 것으로 아는데, 정확히 무엇을
뜻하는 것인가요 ?
struct name {
int namelen;
char namestr[]; /* flexible array member */
};
#include <stdlib.h>
#include <string.h>
struct name {
char namestr[]; /* flexible array member */
};
struct foo {
char ch;
int i[];
};
11.12 Types
#define __STDC_LIMIT_MACROS
#include <stdint.h>
207
CHAPTER 12. THE STANDARD I/O LIBRARY 208
char c;
while ((c = getchar()) != EOF) ...
while (!feof(infp)) {
fgets(buf, MAXLINE, infp);
fputs(buf, outfp);
}
while (!feof(fp))
fgets(line, max, fp);
ter 15 참고 바랍니다.
CHAPTER 12. THE STANDARD I/O LIBRARY 213
#include <locale.h>
char *
commaprint(unsigned long n)
{
static int comma = ’\0’;
static char retbuf[30];
char *p = &retbuf[sizeof(retbuf) - 1];
int i = 0;
if (comma == ’\0’) {
struct lconv *lcp = localeconv();
if (lcp != NULL) {
if (lcp->thousands_sep != NULL &&
*lcp->thousands_sep != ’\0’)
comma = *lcp->thousands_sep;
else
comma = ’.’;
}
}
*p = ’\0’;
do {
if (i % 3 == 0 && i != 0)
*-p = comma;
*-p = ’0’ + n % 10;
n /= 10;
i++;
} while (n != 0);
return p;
}
4 * (sizeof(long) * CHAR_BIT + 2) / 3 / 3 + 1
#include <inttypes.h>
#include <stdio.h>
int
main(void)
{
uint_fast16_t foo;
uintmax_t i = UINTMAX_MAX;
...
fprintf(stderr, "foo is %" PRIoFAST16 ".\n", foo);
i);
return 0;
}
double d;
scanf("%f", &d);
short int s;
scanf("%d", &s);
#define WIDTH 3
#define Str(x) #x
#define Xstr(x) Str(x) /* 질문 11.17 참고 */
char fmt[10];
sprintf(fmt, "%%%dd", width);
scanf(fmt, &n);
1234ABC5.678
CHAPTER 12. THE STANDARD I/O LIBRARY 218
#include <stdlib.h>
#define MAXARGS 10
char *av[MAXARGS];
int ac, i;
double array[MAXARGS];
#include <inttypes.h>
#include <stdio.h>
main(void)
{
uint_fast16_t foo;
uintmax_t i = UINTMAX_MAX;
return 0;
}
1 2 3
인 경우나
1
2
3
인 경우 모두 쓸 수 있습니다.
(다른 언어들과 비교해 보면, C, Pascal, 그리고 LISP 이 free-format 이며,
traditional BASIC 과 FORTRAN 이 free-format 이 아닙니다.)
여러분이 꼭 scanf 가 newline 을 다르게 처리하게 만들고 싶다면, “scanset”
directive 를 쓰면 됩니다 :
scanf("%d%*[\n]", &n);
int n;
char str[80];
42
a string
42 a string
int n;
while (1) {
printf("enter a number: ");
if (scanf("%d", &n) == 1)
break;
printf("try again: ");
}
printf("You typed %d\n", n);
123CODE
‘worm’ 은 UNIX finger daemon 이 gets()를 쓴다는 것을 이용, gets()의 버퍼를 overflow 시켜서,
함수의 return address 를 바꾸어 코드의 흐름이 다른 곳으로 가도록 만들어 버립니다.
CHAPTER 12. THE STANDARD I/O LIBRARY 226
errno = 0;
printf("This\n");
printf("is\n");
printf("a\n");
printf("test.\n");
if (errno != 0)
fprintf(stderr, "printf failed: %s\n", strerror(errno));
FILE *infp;
myfopen("filename.dat", infp);
FILE *
myfopen(char *filename)
{
FILE *fp = fopen(filename, "r");
return fp;
}
그 다음 다음과 같이 씁니다.
FILE *infp;
infp = myfopen("filename.dat");
FILE *infp;
myfopen("filename.dat", &infp);
fopen("c:\newdir\file.dat", "r");
Q 12.30 파일의 내용을 고치려고 합니다. 일단 "r+" 모드로 파일을 연 다음, 원하는
문자열을 읽고 다시 이 문자를 쓰려고 했으나 제대로 동작하지 않습니다.
FILE *ofp;
struct mystruct {
char c;
long int i32;
int i16;
}
s.c = getc(fp);
putc(s.c, fp);
Library Functions
Sorting: 13.8–13.11
237
CHAPTER 13. LIBRARY FUNCTIONS 238
Note C99 표준에 새로 추가된 long long 타입을 쓰려면, ll length modifier 를
써야 합니다. 즉 long 을 출력하기 위해 %ld 를 쓴 것처럼, %lld 를 씁니다.
마찬가지로, size_t 타입의 값을 쉽게 출력할 수 있도록 printf, scanf
형태의 함수에 z modifier 를 추가했습니다. 정수 출력에 쓰이는 conversion
인, d, i, o, u, x, X 에 z 를 붙여서 size_t 를 쉽게 출력할 수 있습니다. 예
를 들면 :
size_t sz;
...
printf("%zu\n", sz);
*dest = ’\0’;
strncat(dest, source, n);
#include <string.h>
char string[] = "this is a test";
/* not char *; see Q16.6 */
char *p;
for (p = strtok(string, " \t\n"); p != NULL;
p = strtok(NULL, " \t\n"))
printf("\"%s\"\n", p);
#include <ctype.h>
int
makeargv(char *string, char *argv[], int argvsize)
{
char *p = string;
int i;
int argc = 0;
else {
argv[argc] = 0;
break;
}
char *av[10];
int i, ac = makeargv(string, av, 10);
for (i = 0; i < ac; i++)
printf("\"%s\"\n", av[i]);
#include <string.h>
char *p = string;
13.2 Sorting
#include <stdlib.h>
char *strings[NSTRINGS];
int nstrings;
struct mystruct {
int year, month, day;
}
#include <stdlib.h>
struct mystruct dates[NDATES];
int ndates;
/* ndates cells of dates[] are to be sorted */
qsort(dates, ndates, sizeof(struct mystruct),
mystructcmp);
{
struct mystruct *p1 = *(struct mystruct * const *)p1;
struct mystruct *p2 = *(struct mystruct * const *)p2;
#include <stdio.h>
#include <time.h>
int main()
{
time_t now;
time(&now);
printf("It’s %.24s.\n", ctime(&now));
return 0;
}
[C89] § 7.12
[H&S] § 18
#include <stdio.h>
#include <time.h>
tm1.tm_mon = 10 - 1;
tm1.tm_mday = 24;
tm1.tm_year = 1994 - 1900;
tm1.tm_hour = tm1.tm_min = tm1_tm_sec = 0;
tm1.tm_isdst = -1;
tm1.tm_mday -= 90;
if (mktime(&tm1) == -1)
fprintf(stderr, "mktime failed.\n");
else
printf("%d/%d/%d\n",
tm1.tm_mon + 1, tm1.tm_mday, tm1.tm_year + 1900);
tm1.tm_mon = 2 - 1;
tm1.tm_mday = 28;
tm1.tm_year = 2000 - 1900;
tm1.tm_hour = tm1.tm_min = tm1.tm_sec = 0;
tm1.tm_isdst = -1;
tm2.tm_mon = 3 - 1;
tm2.tm_mday = 1;
CHAPTER 13. LIBRARY FUNCTIONS 252
t1 = mktime(&tm1);
t2 = mktime(&tm2);
if (t1 == -1 || t2 == -1)
fprintf(stderr, "mktime failed\n");
else {
long d = (difftime(t2, t1) + 86400L/2) / 86400L;
printf("%ld\n", d);
}
int n = 90;
int month, day, year;
FromJul(ToJul(10, 24, 1994) + n, &month, &day, &year);
#define a 16807
#define m 2147483647
#define q (m / a)
#define r (m % a)
X ← (aX + c) mod m
double PMrand(void);
return (double)seed / m;
rand() % N /* POOR */
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
rand() / (RAND_MAX / N + 1)
do {
r = rand();
} while (r >= y);
return r / x;
M + rand() / (RAND_MAX / (N - M + 1) + 1)
(int)(drand48() * N)
Q 13.17 프로그램을 실행시킬 때마다, rand()는 일정한 순서로 난수를 (random num-
ber) 발생시킵니다. 왜 그러죠 ?
#include <stdlib.h>
#include <time.h>
Q 13.20 How can I generate random numbers with a normal or Gaussian distri-
bution?
#include <stdlib.h>
#include <math.h>
#define NSUM 25
double gaussrand()
CHAPTER 13. LIBRARY FUNCTIONS 259
{
double x = 0;
int i;
for (i = 0; i < NSUM; i++)
x += (double)rand() / RAND_MAX;
x -= NSUM / 2.0;
x /= sqrt(NSUM / 12.0);
return x;
}
#include <stdlib.h>
#include <math.h>
#define PI 3.141592654
double gaussrand()
{
static double U, V;
static int phase = 0;
double z;
if (phase == 0) {
U = (rand() + 1.) / (RAND_MAX + 2.);
V = rand() / (RAND_MAX + 1.);
Z = sqrt(-2 * log(U)) * sin(2 * PI * V);
}
else
Z = sqrt(-2 * log(U)) * cos(2 * PI * V);
phase = 1 - phase;
return Z;
}
CHAPTER 13. LIBRARY FUNCTIONS 260
#include <stdlib.h>
#include <math.h>
double gaussrand()
{
static double V1, V2, S;
static int phase = 0;
double X;
if (phase == 0) {
do {
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
} while (S >= 1 || S == 0);
phase = 1 - phase;
return X;
}
These methods all generate numbers with mean 0 and standard devia-
tion 1. (To adjust to another distribution, multiply by the standard de-
viation and add the mean.) Method 1 is poor “in the tails” (especially
if NSUM is small), but methods 2 and 3 perform quite well. See the
references for more information.
ates”
Marsaglia and Bray, “A Convenient Method for Generating Normal Vari-
ables”
Abramowitz and Stegun, Handbook of Mathematical Functions
Press et al., Numerical Recipes in C § 7.2 pp. 288-90.
#include <stdlib.h>
double drand48(void)
{
return rand() / (RAND_MAX + 1.);
}
double drand48(void)
{
double x = 0;
double denom = RAND_MAX + 1.;
double need;
}
return x;
}
Before using code like this, though, beware that it is numerically sus-
pect, particularly if (as is usually the case) the period of rand is on the
order of RAND_MAX. (If you have a longer-period random number gener-
ator available, such as BSD random, definitely use it when simulating
drand48.)
Q 13.24 오래된 프로그램을 포팅하려고 합니다. 그런데 index, rindex, bcopy, bcmp,
bzero 함수가 정의되어 있지 않은 것 같습니다. “undefined external” 이라
는 에러가 뜨는 군요.
References [PCS] § 11
Note index, rindex, bcopy, bcmp, bzero 모두 4.3 BSD 시스템에서 제공하는
함수로서, C 표준이 아닙니다. 이들 함수는 특히, 오래된 network 관련 프
로그램 소스에서 많이 쓰며, 1:1 대응되는 표준 함수들이 (위에서 소개한
것처럼) 있으니, 표준 함수들을 쓰시기 바랍니다. 기존 소스를 수정할 수
없는 상황이라면, 이들 함수를 매크로로 표준 함수로 바꿔서 만들 수 있습
니다. Richard Stevens 씨는 UNIX Network Programming 책에서 모든 코
드가 4.3 BSD 함수를 쓰도록 만들고 헤더 파일 <unp.h> 에서 표준 함수로
(매크로를 써서) 예전 함수를 만들어 두었습니다.
References [Stevens98]
Answer 대부분 linker 들은, 주어진 오브젝트 파일과 라이브러리 파일들을 단 한번씩
만 조사하고, 함수 호출에 필요한 정의가 발견되면 함께 링크합니다. 만약
주어진 파일 목록에서 (한번 시도해서) 함수 정의를 찾지 못한다면, 심볼이
정의되어 있지 않다고 에러가 생깁니다. 따라서, linker 에게 전달하는 오브
젝트 파일들과 라이브러리 파일들의 순서가 매우 중요합니다 ; 보통의 경우,
라이브러리 파일을 마지막에 써 두는 것이 좋습니다.
예를 들어, 대부분 UNIX 시스템에서 다음과 같이 명령을 실행하면, 보통
동작하지 않습니다 :
cc -lm myproc.c
cc myproc.c -lm
Floating Point
266
CHAPTER 14. FLOATING POINT 267
double a, b;
...
if (a == b) /* WRONG */
이렇게 합니다 :
#include <math.h>
(int)(x + 0.5)
Q 14.12 I’m looking for some code to do: Fast Fourier Transforms (FFT’s), ma-
trix arithmetic (multiplication, inversion, etc.), complex arithmetic?
Answer Ajay Shah has prepared a nice index of free numerical software which
has been archived pretty widely; one URL is
ftp://ftp.math.psu.edu/pub/FAQ/numcomp-free-c.
덧붙여 질문 18.13,18.15c, 18.16 도 참고하시기 바랍니다.
Variable-Length Argument
Lists
271
CHAPTER 15. VARIABLE-LENGTH ARGUMENT LISTS 272
printf("%d", n);
char *retbuf;
va_list argp;
char *p;
if (first == NULL)
return NULL;
len = strlen(first);
va_start(argp, first);
va_end(argp);
if (retbuf == NULL)
return NULL; /* error */
(void)strcpy(retbuf, first);
va_end(argp);
return retbuf;
}
#include <stdio.h>
#include <stdarg.h>
void
miniprintf(char *fmt, ...)
{
char *p;
int i;
unsigned u;
char *s;
va_list argp;
va_start(argp, fmt);
switch (*++p) {
case ’c’:
i = va_arg(argp, int);
CHAPTER 15. VARIABLE-LENGTH ARGUMENT LISTS 276
case ’d’:
i = va_arg(argp, int);
if (i < 0) {
/* XXX won’t handle INT_MIN */
i = -i;
putchar(’-’);
}
fputs(baseconv(i, 10), stdout);
break;
case ’o’:
u = va_arg(argp, unsigned int);
fputs(baseconv(u, 8), stdout);
break;
case ’s’:
s = va_arg(argp, char *);
fputs(s, stdout);
break;
case ’u’:
s = va_arg(argp, unsigned int);
fputs(baseconv(u, 10), stdout);
break;
case ’x’:
u = va_arg(argp, unsigned int);
fputs(baseconv(u, 16), sttout);
break;
case ’%’:
putchar(’%’);
break;
CHAPTER 15. VARIABLE-LENGTH ARGUMENT LISTS 277
}
va_end(argp);
}
}
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#include <varargs.h>
#include <string.h>
char *vstrcat(va_alist)
va_dcl /* no semicolon */
{
int len = 0;
char *retbuf;
va_list argp;
char *p;
CHAPTER 15. VARIABLE-LENGTH ARGUMENT LISTS 279
va_start(argp);
va_end(argp);
if (retbuf == NULL)
return NULL; /* error */
retbuf[0] = ’\0’;
va_end(argp);
return retbuf;
}
#include <stdio.h>
#include <varargs.h>
void error(va_alist)
va_dcl /* no semicolon */
{
char *fmt;
CHAPTER 15. VARIABLE-LENGTH ARGUMENT LISTS 280
va_list argp;
fprintf(stderr, "error: ");
va_start(argp);
fmt = va_arg(argp, char *);
vfprintf(stderr, fmt, argp);
va_end(argp);
fprintf(stderr, "\n");
}
int f(...)
{
}
Q 15.10 가변 인자를 처리하는 함수에서 float 인자를 처리하지 못합니다. 왜 va_arg(argp, float)
을 쓰면 동작하지 않을까요 ?
va_arg(argp, funcptr)
다음과 같이 확장됩니다 :
You can pick apart variable-length argument lists at run time, as we’ve seen.
But you can create them only at compile time. (We might say that strictly
2이 확장이 올바르려면 다음과 같아야 합니다 :
(*(int (**)())(((argp) += sizeof(int (*)())) - sizeof(int (*)())))
CHAPTER 15. VARIABLE-LENGTH ARGUMENT LISTS 283
speaking, there are no truly variable-length argument lists; every actual argu-
ment list has some fixed number of arguments. A vararg function merely has
the capability of accepting a different length of argument list with each call.)
If you want to call a function with a list of arguments created on the fly at
run time, you can’t do so portably.
#include <stdio.h>
#include <stdarg.h>
va_end(argp);
exit(EXIT_FAILURE);
}
Strange Problems
It’s not even worth asking the rhetorical question, Have you ever had a baf-
fling bug that you just couldn’t track down? Of course you have; everyone
has. C has a number of splendid “gotcha!s” lurking in wait for the unwary;
this chapter discusses a few of them. (In fact, any language powerful enough
to be popular probably has its share of surprises like these.)
286
CHAPTER 16. STRANGE PROBLEMS 287
printf("%d\n", i);
}
myprocedure;
myprocedure();
struct mystruct {
char c;
long int i32;
int i16;
};
Answer The problem is that you’re playing too fast and loose with your pointers.
어떤 시스템들은 데이터 값들이 정확히 align 되어 있어야만 그 값을 access
할 수 있습니다. 예를 들어, 2-byte short int 는 2 의 배수 형태를 띄는
주소값에서만 읽을 수 있으며, 4-byte long int 는 4 의 배수 형태를 띄어야
만 access 가 가능합니다. (질문 2.12 참고). (아무 곳이나 가리킬 수 있는)
char * 타입의 포인터를 강제로 int * 나 long int * 포인터로 바꿔 쓰면,
프로세서에게 multitype 값을 제대로 align 되지 않은 곳에 access 하게 만들
게 됩니다.
주어진 역할을 좀 더 올바르게 수행할 수 있는 방법은 다음과 같습니다 :
CHAPTER 16. STRANGE PROBLEMS 292
s.c = *p++;
This code also gives you control over byte order. (This example, though,
assumes that a char is 8 bits and the long int and int being unpacked
from the “external structure” are 32 and 16 bits, respectively.) (비슷한
코드를 보여주는) 질문 12.42 를 보기 바랍니다.
덧붙여 질문 4.5 도 참고하시기 바랍니다.
2 Yes, the name “core” derives ultimately from old ferrite core memories.
Chapter 17
Style
294
CHAPTER 17. STYLE 295
if(!strcmp(s1, s2))
이것이 좋은 스타일일까요 ?
if (x = 0)
if (0 = x)
298
CHAPTER 18. TOOLS AND RESOURCES 299
http://www.qucis.queensu.ca/Software-Engineering/Cmetrics.html
http://www.gnu.org/software/indent/
http://www.gnu.org/software/gcc/
http://www.cs.princeton.edu/software/lcc/
References [Darwin]
Gimpel Software
3207 Hogarth Lane
Collegeville, PA 19426 USA
(+1) 610 584 4261
[email protected]
http://lclint.cs.virginia.edu/
http://www.splint.org/
http://www-h.eng.cam.ac.uk/help/tpl/languages/C/teaching_C/
http://www.strath.ac.uk/CC/Courses/CCourse/CCourse.html
http://www-isis.ecs.soton.ac.uk/computing/c/Welcome.html
CHAPTER 18. TOOLS AND RESOURCES 304
http://www.eskimo.com/~scs/cclass/cclass.html
http://www.lysator.liu.se/c/index.html
http://www.cyberdiem.com/vin/learn.html
http://www.eskimo.com/~scs/C.html
• http://www.csd.uwo.ca/ jamie/.Refs/.Footnotes/C-annotes.html
• http://www.eskimo.com/ scs/cclass/cclass.html
• http://www.lysator.liu.se/c/c-errata.html#main
http://www.skwc.com/essent/cyberreviews.html
http://bach.cis.temple.edu/accu/bookcase
http://www.accu.org/accu
http://www.careferencemanual.com/
http://www.gnu.org/software/glibc/
• http://www.cs.man.ac.uk/standard c/ index.html
• http://www.dinkumware.com/htm cl/index.html.
pub/packages/development/libraries/defunc-1.3.tar.Z
http://www.nullstone.com/
pub/language/C/Publib/
http://www.snippets.org/
• ftp://gatekeeper.dec.com/pub/usenet/comp.sources.unix/
• ftp://ftp.uu.net/usenet/comp.sources.unix/
http://www.gnu.org/
Chapter 19
System Dependencies
310
CHAPTER 19. SYSTEM DEPENDENCIES 311
• comp.os.msdos.programmer,
• comp.unix.questions
Answer 문자를 장치에 보내는 방법을 알고 있다면 (질문 19.8 참고), Escape se-
quence 를 보내는 방법은 매우 쉽습니다. ASCII 로 ESC 는 033, (10 진수
로 27), 이므로 :
fprintf(ofd, "\033[J");
http://www.gnu.org/software/plotutils/plotutils.html
References K&R § 1, § 7
fopen("c:\newdir\file.dat", "r")
fopen("c:\\newdir\\file.dat", "r")
fopen("c:/newdir/file.dat", "r")
long int i;
CHAPTER 19. SYSTEM DEPENDENCIES 325
#include <signal.h>
signal(SIGINT, SIG_IGN);
http://kipper.york.ac.uk/~vic/sock-faq/
Miscellaneous
328
CHAPTER 20. MISCELLANEOUS 329
int x = 1;
if (*(char *)&x == 1)
printf("little-endian\n");
else
printf("big-endian\n");
20.3 Efficiency
a ^= b;
b ^= a;
a ^= b;
int t = a;
a = b;
b = t;
Q 20.20b Is C a great language, or what? Where else could you write something
like a+++++b ?
Answer Well, you can’t meaningfully write it in C, either. The rule for lexical
analysis is that at each point during a straightforward left-to-right scan,
the longest possible token is determined, without regard to whether the
resulting sequence of tokens makes sense. The fragment in the question
is therefore interpreted as
a ++ ++ + b
assert(p != NULL);
CHAPTER 20. MISCELLANEOUS 338
References [H&S] p. xviii, § 1.1.5 p. 6, § 2.8 pp. 36–7, § 4.9 pp. 104–107
CHAPTER 20. MISCELLANEOUS 340
20.7 Algorithms
Answer 2000 년은 윤년이 (leap year) 맞습니다. 그리고 윤년을 계산하는 공식은 다
음과 같습니다 :
20.8 Trivia
where count bytes are to be copied from the array pointed to by from
to the memory location pointed to by to (which is a memory- mapped
device output register, which is why to isn’t incremented). It solves the
problem of handling the leftover bytes (when count isn’t a multiple of
8) by interleaving a switch statement with the loop which copies bytes 8
at a time. (Believe it or not, it is legal to have case labels buried within
blocks nested in a switch statement like this. In his announcement of the
technique to C’s developers and the world, Duff noted that C’s switch
syntax, in particular its “fall through” behavior, had long been contro-
versial, and that “This code forms some sort of argument in that debate,
but I’m not sure whether it’s for or against.”)
http://www.ioccc.org/index.html
rtfm.mit.edu pub/usenet/news.answers/C-faq/
ftp.uu.net usenet/news.answers/C-faq
http://www.eskimo.com/~scs/C-faq/top.html
http://www.faqs.org/faqs/
http://www.eskimo.com/~scs/C-faq/book/Errta.html
CHAPTER 20. MISCELLANEOUS 345
또는 ftp.eskimo.com 의 u/s/scs/ftp/C-faq/book/Errta 로 구할 수도
있습니다.
각각의 문서들은 매달 흥미로운 질문들에 대한 답변이 아니라, 전체 질문 /
답변 목록을 유지하고 있습니다. 따라서 오래된 버전은 필요치 않을 것입
니다.
http://www.cinsk.org/cfaqs/
Extensions
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
346
CHAPTER 21. EXTENSIONS 347
void
error(int status, int errnum, const char *msg, ...)
{
va_list argptr;
if (error_print_progname)
(*error_print_progname)();
else {
fflush(stdout);
fprintf(stderr, "%s: ", program_name);
}
va_start(argptr, msg);
vfprintf(stderr, msg, argptr);
va_end(argptr);
++error_message_count;
if (errnum)
fprintf(stderr, ": %s", strerror(errnum));
putc(’\n’, stderr);
fflush(stderr);
if (status)
exit(status);
}
#include <stdio.h>
#include <errno.h>
int
main(void)
{
FILE *fp;
char *filename = "sample.dat";
fp = fopen(filename, "r");
if (fp == NULL)
error(EXIT_FAILURE, errno,
"cannot open file %s.", filename);
/* ... */
}
Answer atoi 는 주어진 문자열을 10 진수로 해석해서 int 로 바꾸어 주지만, 에러는
처리해 주지 않습니다. 다시 말해서 입력 문자열을 10 진수로 처리할 수 없
을 때에는 대개 0 을 리턴합니다.
따라서 다음과 같은 함수를 만들어 쓰는 것이 좋습니다 :
#include <errno.h>
int
convint(long int *d, const char *s)
{
char *p;
long int i;
*d = i;
return 0;
}
void
CHAPTER 21. EXTENSIONS 350
foo(void)
{
char instr[80];
int i;
http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
buf = *lineptr;
numbytes = *n;
ptr = buf;
cont = 1;
while (cont) {
/* fill buffer - leaving room for nul-terminator */
while (--numbytes > 0) {
if ((ch = getc(fp)) == EOF) {
CHAPTER 21. EXTENSIONS 352
cont = 0;
break;
}
else {
*ptr++ = ch;
if (ch == ’\n’) {
cont = 0;
break;
}
}
}
if (cont) {
/* Buffer is too small so reallocate a larger buffer. */
pos = ptr - buf;
newsize = (*n << 1);
buf = realloc(buf, newsize);
if (!buf) {
cont = 0;
break;
}
int main(void)
{
char *line = NULL;
ssize_t len;
size_t size;
return 0;
}
21.2 Debugging
Q 21.5 이 글은 어떤 툴로 만든 것인가요 ?
21.3 Internationalization
References [Ken99] p. 17
ISO C Standard
Consideration
Q 22.1 Terminology
Answer access <execution-time action> to read or to modify the value of an ob-
ject.
Note 1 Where only one of these two actions is meant, “read” or
“modify” is used.
Note 2 “Modify” includes the case where the new value being stored
is the same as the previous value.
Note 3 Expressions that are not evaluated do not access object.
alignment requirement that objects of a particular type be located on
storage boundaries with addresses that are particular multiples of
a byte address
356
CHAPTER 22. ISO C STANDARD CONSIDERATION 357
[Darwin] Ian F. Darwin, Checking C Programs with lint, O’Reilly, 1988, ISBN
0-937175-30-7.
[H&S] Samuel pp. Harbison and Guy L. Steele, Jr., C: A Reference Manual,
Fourth Edition, Prentice-Hall, 1995, ISBN 0-13-326224-3. [H&S]
[H&S2002] Samuel pp. Harbison and Guy L. Steele, Jr., C: A Reference Man-
ual, Fifth Edition, Prentice-Hall, 2002, ISBN 0-13-089592-X. [H&S5]
[PCS] Mark R. Horton, Portable C Software, Prentice Hall, 1990, ISBN 0-13-
868050-7.
359
BIBLIOGRAPHY 360
[SUS] Single UNIX Specification Version 3 – IEEE Std 1003.1, 2004 Edition,
Single UNIX Specification Version 3 Formerly known as [POSIX].
http://www.unix.org/version3/
[Plauger] P.J. Plauger, The Standard C Library, Prentice Hall, 1992, ISBN 0-
13-131509-9.