-
Notifications
You must be signed in to change notification settings - Fork 4
/
standard.tex
1630 lines (1422 loc) · 73.7 KB
/
standard.tex
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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\chapter{ANSI/ISO Standard C} \label{chap:standard}
% chapter 11: standard
The release of the ANSI C Standard (X3.159-1989) in 1990 (now superseded by
ISO 9899:1990) and its ongoing revisions) marked a major step in C's
acceptance as a stable language. The standard clarified many existing
ambiguities in the language, but it introduced a few new features and
definitions that are occasionally troublesome. Misunderstandings also arise
when an ambiguity was resolved contrary to someone's experience or when people
with pre-ANSI compilers try to use code written since the standard became
widely adopted.
Standard C can be referred to in several ways. It was originally written by
a committee (X3J11) under the auspices of the American National Standards
Institute, so it's often called ``ANSI C.'' The ANSI C Standard was adopted
internationally by the International Organization for Standardization, so it's
sometimes called ``ISO C.'' ANSI eventually adopted the ISO version
(superseding the original), so it's now often called ``ANSI/ISO C.''
Unless you're making a distinction about the wording of the original ANSI
standard before ISO's modifications, there's no important difference among
these terms, and it's correct to simply refer to ``the C Standard'' or
``standard C.'' (When the subject of C is implicit in the discussion, it's
also common to use the word ``standard'' by itself, often capitalized.)
% 아래 단락은 새로 추가한 것임.
C 언어 표준은 항상 진행중입니다. 현재 C99까지 나왔으며, 앞으로도 다음 표준이
나올 수 있습니다. 여기에서는 \cite{rational2}에 나온 C89 위원회의 원칙에 대해
몇가지 간단히 소개하겠습니다:
\begin{itemize}
\item Existing code is important, existing implementations are not.
현존하는 C 코드의 중요성을 인식하고, 가능하면 기존의 코드가 변화없이
동작할 수 있도록 합니다.
\item C code can be portable.
C 언어는 비록 PDP-11에서 동작하는 UNIX 시스템에서 태어났지만, 현존하는
모든 시스템에서 표준 C 언어를 (언어 및 라이브러리) 구현 가능하도록 합니다.
\item C code can be non-portable.
C 표준이 프로그래머가 이식성이 높은 프로그램을 작성할 수 있도록 해 주지만,
그렇다고 프로그래머가 고수준 어셈블러처럼 C 언어를 쓰는 것을 제한하지
않습니다. 시스템 의존적인 코드를 만들 수 있는 것도 C 언어의 장점 중
하나이기 때문입니다.
\item Avoid ``quite changes.''
현존하는 코드의 의미를 바꾸는 변화는 문제가 될 수 있습니다. 적어도 이런
문제가 있다면 항상 쉽게 알 수 있는 방법을 제공해야 하며, 가능한 이런
은근슬쩍 의미를 바꾸지 않도록 할 것이며, 이런 변화가 있다면
표준과 Rationale에 ``QUITE CHANGE''로 명시할 것입니다.
\item A standard is a treaty between implementor and programmer.
시스템(컴파일러) vendor와 개발자들이 좀 더 자세히 이해할 수 있도록,
여러 수치 제한이 추가됩니다. 하지만, 이런 제한은 표준보다 우수하거나,
표준의 제한을 벗어나는 시스템을 개발하는 것을 막지 않습니다. 이런 제한들은
(\EM{minimum maxima})최고값이 제공할 수 있는 최하위 값의 형태로 제공됩니다.
\item Keep the spirit of C.
기존 C 언어가 가지고 있는 틀을 그대로 유지합니다. 즉,
\begin{itemize}
\item Trust the programmer.
\item Don't prevent the programmer from doing what needs to be done.
\item Keep the language small and simple.
\item Provide only one way to do an operation.
\item Make it fast, even if it is not guaranteed to be portable.
\end{itemize}
\item Support international programming.
\item Codify existing practice to address evident deficiencies.
\item Minimize incompatibilities with C89.
\item Minimize incompatibilities with C++.
\item Maintain conceptual simplicity.
\end{itemize}
\noindent 좀 더 자세한 것은 \cite{rational2}를 참고하기 바랍니다.
\section{The Standard}
% from 11.1
\begin{faq}
\Q{11.1}
``ANSI C 표준''이란 무엇인가요?
\A
1983년, 미국 규격 협회(American National Standards Institute, ANSI)는
C 언어의 표준을 제정하기 위해 X3J11이라는 위원회를 열었습니다.
매우 긴 기간동안 토론한 끝에 이 위원회의 보고서는
1989년 12월 14일 ANSX3.159-1989라는 이름으로 비준받아서, 1990년에
출판되었습니다. 대부분의 내용은 기존의 C 언어에서 가져온 것이며,
몇몇은 C++에서 (대부분 함수 prototype에 대한 것) 가져온 것입니다.
그리고 (논쟁의 여지가 있던 3중 음자(trigraph) 문자 시퀀스를 포함한)
다국적 문자 세트를 지원하는 기능도 포함시켰습니다. ANSI C 표준은
C run-time 라이브러리도 표준화시켰습니다.
그 후에 국제 표준 기구인 ISO\footnote{International Organization
for Standardization}는 미국 표준인 X3.159를
국제 표준인 ISO/IEC 9899:1990으로 바꿔서 국제 표준으로 만들었습니다.
이 표준에서는 ANSI의 표준을 정정하고 보충한 것이 대부분이었기 때문에
흔히 `ANSI/ISO 9899-1990' [1992] 라고 부릅니다.
1994년 `Technical Corrigendum 1(TC1)'은 표준에서 약 40 가지를
수정하였습니다. 대부분 수정은 부분적으로 명확한 설명이 필요한 것에
보충 설명을 단 것입니다. 그리고 `Normative Addendum 1(NA1)'은 약
50 페이지 분량의 새로운 내용을 추가했으며, 대부분이
국제화(internationalization\footnote{이 단어가 너무 길기 때문에
보통 i18n으로 부르기도 합니다. 여기에서 18은 이 단어의 총 글자
수입니다.})에 관한 함수 설명입니다.
1995년 TC2는 몇가지 정정 사항을 추가했습니다.
이 글을 쓸 때, 표준의 완전한 개정판은 이제 막바지 작업에
들어 갔습니다. 새로운 표준은 현재 ``\cite{c9x}''라고 이름이 붙었고,
1999년 말에 완성될 거라는 뜻을 나타냅니다. (이 글의 많은
부분도 새로운 \cite{c9x}를 반영하려고 수정되었습니다.)
오리지널 ANSI 표준은 많은 부분에서 결정한 부분에 대한 설명과,
작은 문제들에 대한 논의를 포함한 ``\cite{rationale} (이론적 해석)''을
포함하고 있습니다. 몇 가지는 이 글에 이미 포함되었습니다.
(\cite{rationale} 자체는 ANSI 표준 X3.159-1989에 포함된 부분이 아니지만
정보 제공 목적으로만 제공되는 것이며, ISO 표준에 포함되는 내용도
아닙니다. \cite{c9x} 용으로 새 판이 준비되고 있는 상황입니다.)
\T
\cite{hs5} 소개 부분에 나온 내용을 인용 및 요약하면
크게, C 언어는 네번의 변화를 거쳤습니다.
첫째, Brian Kernighan씨와 Dennis Ritchie씨가 1978년에 쓴
\EM{The C Programming Language}에서 소개한 C 언어입니다. 보통
``K\&R''이라고 부르며, 1980년대에 쓰였던 모든 C 언어를 ``traditional
C''라고 합니다.
둘째, 표준을 정해 놓는 것이, C 언어가 널리 퍼지게 하는데 도움이
될 것이라는 믿음에서, 앞에서 소개한 ANSI 표준이 만들어졌습니다.
(지금은 NCITS J11이 된) X3J11 위원회는 1989년에 C 언어 표준과
런타임 라이브러리를 ``\EM{American National Standard X3.159-1989}''로
공식화 했으며, 보통 ``ANSI C''라고 부릅니다. 이는 곧 국제 표준으로
받아들여져, 국제 표준인 ISO/IEC 9899:1990으로 등록되었습니다.
ANSI C와 이 국제 C 언어 표준과 차이점은 거의 없습니다. 그리고
이 국제 표준을 보통 ``Standard C''라고 부릅니다. 그러나 이 표준은
또 변했기 때문에, 이 것을 ``Standard C (1989)''로 부르거나,
줄여서 ``C89''라고 합니다.
셋째, WG14 그룹은 C89에 대한 두 문서를 만들었는데
하나는 `Technical Corrigenda'이며
(버그 수정 문서), 또 하나는 `Amendment (확장)'입니다. 이들이 반영된
표준은, ``C89 with Amendment 1'' 또는 ``C95''라고 부릅니다.
넷째, WG14는 계속 작업을 거듭했고, 그 추가 및 확장 사항들이
다시 반영되어, 1999년에 표준으로 제정되었습니다. 이는
``\EM{ISO/IEC 9899:1999}'' 또는, 줄여서 ``C99''라고 부르며, 이 것이
가장 최신의 표준입니다.
참고로, Bjarne Stroustrup씨가 1980년 초반에 디자인한 C++은 현재
가장 인기있는 언어 중의 하나이며, 이 언어는 C 언어를 기초로 만들어
졌습니다. 이 C++ 언어도 역시 표준화가 (1998년) 이루어졌으며, 그 결과,
\EM{ISO/IEC 14882:1998} 또는 간단히 ``Standard C++''이라고 부릅니다.
표준화가 이루어진 년도를 주의깊게 보았다면, C 언어 최신 표준이
C++ 언어의 표준이 제정된 다음에 개정된 것을 알 수 있습니다.
물론 단순히 이 사실 만으로 알 수 있는 것은 아니지만, 사실 표준 C++
언어가, 표준 C 언어의 모든 점을 포함하고 있지 않습니다.
따라서 정확히 말해서, ``C 언어는 C++ 언어의 부분집합이다'' 또는
``C++ 언어는 C 언어를 포함한다''라는 말은 모두 틀린 말입니다.
물론 C++ 언어가 C 언어의 대부분을 포함하고 있지만, 전부는 아닙니다.
따라서, C 언어 표준을 완벽하게 지원하도록 만든 코드가 C++ 언어 표준에
맞지 않을 가능성이 있습니다. C 언어와 C++ 언어에서 완벽하게 동작하는
코드를 (어떤 사람들은) ``Clean C''라고 부릅니다.
앞 답변에서 ``C9X''라고 부르는 것은, 1990년대에 아직, 새 C 표준이
정해지지 않았을 때, (정확한 제정 연도를 몰랐기 때문에) 붙여진
이름입니다. 이제는 1999년에 제정된 것을 알기 때문에 ``C99''라고
부르는 것이 올바른 표현입니다.
\R
\cite{hs5} \S\ 1.1 \Page{4--5} \\
\cite{rational2} \S\ 0
\end{faq}
\begin{faq}
\Q{11.2}
표준 문서를 어디서 얻을 수 있죠?
\A
미국이라면 다음 주소에서 사본을 신청할 수 있습니다:
\begin{verbatim}
American National Standards Institute
11 W. 42nd St., 13th floor
New York, NY 10036 USA
(+1) 212 642 4900
\end{verbatim}
\noindent 또는 다음 주소도 가능합니다:
\begin{verbatim}
Global Engineering Documents
15 Inverness Way E
Englewood, CO 80112 USA
(+1) 303 397 2715
(800) 854 7179 (U.S. & Canada)
\end{verbatim}
다른 나라들에서는 제네바(Geneva)에 있는 ISO에 주문하거나
각 국의 표준 위원회에 연락하시기 바랍니다:
\begin{verbatim}
ISO Sales
Case Postale 56
CH-1211 Geneve 20
Switzerland
\end{verbatim}
(또는 \verb+http://www.iso.ch+를 방문하거나, \verb+comp.std.internat+
FAQ 리스트에서 Standards.Faq를 참고하기 바랍니다).
저자가 마지막으로 검사했을 때, ANSI에서 주문하려면 130.00\$가
필요했으며, GLobal에서 주문할 때에는 400.50\$가 필요했습니다.
(\cite{rationale}을 포함한) 오리지널 X3.159는 ANSI에서 205.00\$,
Global에서는 162.50\$가 필요했습니다. ANSI에서는 표준 문서를
판매한 수익금으로 운영하기 때문에 전자 출판 형식으로는 제공해주지
않습니다.
미국이라면 (\cite{rationale}를 포함한) 오리지널 ANSI X3.159의 사본을
``FIPS PUIB 160''으로 다음 주소에서 주문할 수 있을 것입니다:
\begin{verbatim}
National Technical Information Service (NTIS)
U.S. Department of Commerce
Springfield, VA 22161
703 487 4650
\end{verbatim}
Herbert Schildt씨가 해설한(annotated) ``Annotated ANSI C Standard''는
ANSI가 아닌 ISO 9899를 설명하고 있습니다; Osborne/McGraw-Hill에서
출판되었으며, ISBN 0-07-881952-0이며, 대략 \$40 선에서 판매되고
있습니다. 표준과 이 책의 가격 차이는 대부분 저자가 단
해설(annotation) 가격입니다: 그러나 많은 에러와 너무 많은 생략으로
평판이 좋지 않습니다. net의 대부분 사람들은 아예 이 책을 무시합니다.
Clive Feather씨는 이 책에 대한 서평을 썼고 아래의 URL에서 볼 수
있습니다:
\begin{verbatim}
http://www.lysator.liu.se/c/schildt.html
\end{verbatim}
\cite{rationale} 문서는 (완전한 표준은 아님) anonymous FTP로
\verb+ftp.uu.net+의 (질문 \ql{18.16} 참고)
\verb+doc/standards/ansi/X3.159-1989+ 디렉토리에서
얻을 수 있습니다.
또 \verb+http://www.lysator.liu.se/c/rat/title.html+에서
볼 수도 있습니다. Silicon Press에서 출판되기도 했습니다.
ISBN 0-929306-07-4입니다.
ISO/IEC C9X의 진행판은 JTC1/SC22/WG14 사이트인 아래에서 얻을 수
있습니다:
\begin{verbatim}
http://www.dkuung.dk/JTC1/SC22/WG14/
\end{verbatim}
질문 \ql{11.2b}를 참고하기 바랍니다.
\T
최신 C 표준인 C99의 PDF 버전 (ISO web site에서) 공식 가격은
(2005년 1월 24일자로) 340 CHF입니다. 이 날짜로, 원화 가격은 약
30만원입니다. ANSI를 비롯, 다른 web site에서도
판매하고 있습니다. 구입할 때, 무료로 배포된는 Corrigenda (버그 수정)
문서도 꼭 함께 받으시기 바랍니다. 현재 다음 두 가지가 나와 있습니다:
\begin{itemize}
\item ISO/IEC 9899:1999/Cor 1:2001
\item ISO/IEC 9899:1999/Cor 2:2004
\end{itemize}
\noindent 검색 엔진을 쓸 때, ``9899:1999''로 검색하시면 빨리 찾을
수 있습니다.
\end{faq}
\begin{faq}
\Q{11.2b}
개정된 표준에 대한 정보는 어디에서 얻을 수 있나요?
\A
(\cite{c9x} 진행판을 포함한) 관련된 정보는 다음 웹 사이트에서 찾을 수
있습니다:
\begin{verbatim}
http://www.lysator.liu.se/c/index.html
http://www.dkuug.dk/JTC1/SC22/WG14/
http://www.dmk.com/
\end{verbatim}
\T
\begin{verbatim}
http://www.dkuug.dk/JTC1/SC22/WG14/
\end{verbatim}
\noindent 위 사이트의 새 주소는 다음과 같습니다:
\begin{verbatim}
http://www.open-std.org/jtc1/sc22/wg14/
\end{verbatim}
\end{faq}
\section{Function Prototypes}
% from 11.3
The most significant introduction in ANSI C is the \EM{function prototype}
(borrowed from C++), which allows a function's argument types to be declared.
To preserve backward compatibility, nonprototype declarations are still
acceptable, which makes the rules for prototypes somewhat more complicated.
\begin{faq}
\Q{11.3}
제 ANSI 컴파일러는 다음과 같은 코드를 봤을 때, 함수가 일치하지 않는다고
에러를 발생합니다:
\begin{verbatim}
extern int func(float);
int func(x)
float x;
{ ...
\end{verbatim}
\A
\begin{sloppypar}
그 이유는 새 (스타일) 프로토타입(prototype) 선언인
``\verb+extern int func(float)+''을 오래된 (스타일) 정의인
``\verb+int func(x) float x;+''와 섞어 썼기 때문에 발생합니다.
보통 이 두 스타일을 섞어 쓰는 것이 가능하지만(질문 \ql{11.4} 참고)
이 경우에는 안됩니다.
Traditional C (프로토 타입과 가변 인자 리스트를 제공하지 않는 ANSI C;
질문 \ql{15.2} 참고) 언어에서는 함수에 전달되는 어떤 인자들을
``확장(widen)''시킵니다. 즉 \TT{float}은 \TT{double}로,
\TT{char}나 \TT{short int}는 \TT{int}로 확장시킵니다.
(구 스타일로 정의한 함수에서는, 이렇게 확장되어 전달된 인자가,
함수의 몸체 부분에 들어갈 때, 다시 원래의 크기로 변환됩니다)
따라서 위의 오래된 스타일로 만든 정의는 사실상 \TT{func} 함수를
\TT{double} 타입 인자를 받도록 만든 것입니다. (물론 함수 내부에서
이 인자는 다시 \TT{float} 타입으로 바뀝니다)
\end{sloppypar}
이 문제는 함수 정의에서 새 스타일의 문법을 써서 고칠 수 있습니다:
\begin{verbatim}
int func(float x) { ... }
\end{verbatim}
또는 새 형식의 프로토타입 선언을 구 형식의 정의와
일치하도록 다음과 같이 만들어 주면 됩니다:
\begin{verbatim}
extern int func(double);
\end{verbatim}
\noindent (이 경우, 가능하다면 구 형식의 정의에서 \TT{double}을 쓰도록
바꿔주는 것이 더 깨끗합니다.\footnote{Changing a parameter's type
may require additional changes if the address of that parameter
is taken and must have aparticular type})
``narrow'' 효과를 피하기 위해, ``narrow'' 효과를 발생하는 타입들을
(예를 들어 \TT{char}, \TT{short int}, \TT{float} 등) 함수 인자나
리턴 타입으로 쓰지 않는 편이 안전할 수 있습니다.
질문 \ql{1.25}를 참고하기 바랍니다.
\R
\cite{kr1} \S\ A7.1 \page{186} \\
\cite{kr2} \S\ A7.3.2 \page{202} \\
\cite{c89} \S\ 6.3.2.2, \S\ 6.5.4.3 \\
\cite{rationale} \S\ 3.3.2.2, \S\ 3.5.4.3 \\
\cite{hs} \S\ 9.2 \Page{265--7}, \S\ 9.4 \Page{272--3} \\
\T
함수 호출시, prototype이 확인되지 않다면, 컴파일러는 모든 인자에 대해
default argument promotion을 실시합니다. 즉, \TT{int}보다 작은
정수 타입들은 모두 \TT{int}로, \TT{float}은 \TT{dobule}로 변환하며,
나머지 타입들은 그대로 전달됩니다. 만약,
인자(argument)가 파라메터와 갯수가 다를 경우, undefined behavior가
발생하며, 만약 나중에 함수 prototype이 발견되었는데, 이 함수
prototype이 가변 인자를 받는 것으로 선언되어 있거나, 파라메터들의
타입이, default argument promotion 후의 인자 타입과 서로 다를때에도
undefined behavior가 발생합니다. (마지막 문장은 함수 인자/파라메터 뿐만
아니라, 함수의 리턴 타입에도 적용됩니다.)
이 규칙은 생각보다 좀 더 까다롭습니다. 아래 Reference를 꼭 읽어 보기
바랍니다.
\cite{c99} \S\ 6.5.2.2, \S\ 6.7.5.3 \\
\cite{hs5} \S\ 9.2
\end{faq}
\begin{faq}
\Q{11.4}
함수 구문에서 오래된 형식과 새 형식을 섞어 쓸 수 있나요?
\A
섞어 쓸 수 있긴 하지만 매우 주의해야 합니다. (질문 \ql{11.3}을 꼭
보시기 바랍니다). 현재에는 prototype 형식이 선언과 정의에 모두
사용되고 있습니다. (오래된 형식은 쓸모 없이 되어가고 있기 때문에,
언젠가 공식적으로 제거될 것입니다.)
\R
\cite{ansi} \S\ 3.7.1, \S\ 3.9.5 \\
\cite{c89} \S\ 6.7.1, \S\ 6.9.5 \\
\cite{hs} \S\ 9.2.2 \Page{265--7}, \S\ 9.2.5 \Page{269--70} \\
\cite{c99} \S\ 6.5.2.2 \S\ 6.9.1 \\
\T
일반적으로, 오래된 형식과 섞어 쓰기 위해서는 다음 두 가지 규칙을
지켜야 합니다:
\begin{itemize}
\item 함수의 리턴 타입과 모든 파라메터 타입은 default argument
promotion 후의 타입과 일치하도록 한다. 즉, \TT{int}보다 작은
정수 타입이나 \TT{float}을 쓰지 않는다.
\item 가변 인자를 받는 함수는 오래된 형식으로 만들지 않는다.
\end{itemize}
\R
\cite{hs5} \S\ 9.2.2, \Page{291--292} \S\ 9.2.5 \Page{294--295} \\
GNU Coding Standard \S\ 3.4
\end{faq}
\begin{faq}
\Q{11.5}
컴파일러가 다음 선언을 만나면:
\begin{verbatim}
extern int f(struct x *p);
\end{verbatim}
``struct x introduced in prototype scope''라는 이상한 경고를
발생시킵니다.
\A
C 언어의 블럭 스코프(scope) 규칙에 따르면 함수의 프로토타입에만
선언된 structure는 같은 소스의 다른 구조체와 호환성이 없습니다
이 structure와 tag는 함수의 프로토타입 선언이 끝날 때 스코프를
벗어납니다; 질문 \ql{1.29}를 참고하기 바랍니다.
함수 prototype 앞에 structure 선언을 두어 이 문제를 해결할 수 있습니다.
(보통, prototype과 structure 선언은 같은 헤더 파일에 존재하며,
이렇기 때문에 한쪽이 다른 한쪽을 참조할 수 있습니다.)
만약 prototype에 아직 선언되지 않은 structure를 꼭 쓸 필요가 있다면,
prototype 앞에 다음과 같이 써 줍니다:
\begin{verbatim}
struct x;
\end{verbatim}
\noindent 아무것도 아닌 것 같은 이 선언은 \TT{struct x}
\noindent 이렇게 하면, 이 구조체의 (incomplete) 선언이 파일
스코프를 가지게 되어,
이후에 나올 선언에서 \TT{struct x}를 사용할 때, 같은 \TT{struct x}를
가리키도록 할 수 있습니다.
\R
\cite{ansi} \S\ 3.1.2.1, \S\ 3.1.2.6, \S\ 3.5.2.3 \\
\cite{c89} \S\ 6.1.2.1, \S\ 6.1.2.6, \S\ 6.5.2.3.
\end{faq}
\begin{faq}
\Q{11.6} % 11.6 COMPLETE
다음 코드가 이상하게 동작합니다:
\begin{verbatim}
printf("%d", n);
\end{verbatim}
위에서 \TT{n}은 \TT{long int} 타입입니다. ANSI 함수 prototype이
이런식으로 인자와 파라메터 타입이 서로 일치하지 않을때, (conversion
등으로) 보호해 주지 않나요?
\A
질문 \ql{15.3}을 보기 바랍니다.
\end{faq}
\begin{faq}
\Q{11.7}
\TT{printf}를 쓰기 전에 \verb+<stdio.h>+를 include해야 한다고
들었습니다. 왜 그런가요?
\A
질문 \ql{15.1}을 참고하기 바랍니다.
\end{faq}
\section{The \TT{const} Qualifier}
% from 11.8
Another introduction from C++ is an additional dimension to the type
system: type qualifiers. Type qualifiers can modify pointer types in several
ways (affecting either the pointer or the object pointed to), so qualified
pointer declarations can be tricky. (The questions in this section refer to
\TT{const}, but most of the issues apply to the other qualifiers,
\TT{volatile}, as well.)
\begin{faq}
\Q{11.8}
배열의 크기를 지정할 때, 다음과 같이 상수 값을 쓰면 안되는
이유가 뭔가요?
\begin{verbatim}
const int n = 5;
int a[n];
\end{verbatim}
\A
\TT{const} qualifier는 ``읽기 전용''인 것을 의미합니다;
즉 지정한 오브젝트는 실행할 때 (일반적으로) 변경할 수 없는
run-time 오브젝트입니다.
따라서 이러한 `const' 오브젝트는 상수 수식(constant expression)이
아니기 때문에, 배열의 크기 지정, case label등에 쓰일 수 없습니다.
(이 부분에서 C 언어와 C++이 다릅니다.)
정말로 compile-time 상수가 필요하다면 \verb+#define+으로 (또는
\TT{enum}으로) 상수를 정의하기 바랍니다.
\R
\cite{ansi} \S\ 3.4 \\
\cite{c89} \S\ 6.4 \\
\cite{hs} \S\ 7.11.2,7.11.3 \Page{226--7}
\end{faq}
\begin{faq}
\Q{11.9} % COMPLETE
`\verb+const char *p+'와 `\verb+char * const p+'의 차이는
무엇인가요?
\A
`\verb+const char *p+'는 (`\verb+char const *p+'라고 쓸 수 있음)
상수 문자에 대한 포인터를 선언한 것입니다 (가리키는 문자를 바꿀 수
없는 포인터);
`\verb+char * const p+'는 문자에 대한 상수 포인터를 선언한 것입니다
(문자를 변경할 수는 있지만 포인터를 변경할 수는 없습니다).
해설을 잘 음미해보시기 바랍니다; 질문 \ql{1.21}도 참고하시기 바랍니다.
\R
\cite{ansi} \S\ 3.5.4.1 examples \\
\cite{c89} \S\ 6.5.4.1 \\
\cite{rationale} \S\ 3.5.4.1 \\
\cite{hs} \S\ 4.4.4 \page{81}
\T
아래 예에서, \verb+const_pointer+는 포인터가 상수인 것을
나타냅니다. 그리고,
\verb+pointer_to_const+는 상수를 가리키는 포인터를 나타냅니다:
\begin{verbatim}
int * const const_pointer;
const int *pointer_to_const;
\end{verbatim}
\noindent 즉, \verb+const_pointer+는 포인터가 가리키는 대상을
변경할 수 있으나, 다른 대상을 가리키도록 할 수는 없습니다. 그리고,
\verb+pointer_to_const+는 다른 대상을 가리키도록 할 수 있지만,
포인터가 가리키는 대상을 변경할 수 없습니다.
\R
\cite{hs5} \S\ 4.4.4 \Page{89--91}
\end{faq}
\begin{faq}
\Q{11.10} % 11.10 COMPLETE
\verb+const char **+를 인자로 받는 함수에 \verb+char **+를
전달하면 안되나요?
\A
(어떤 T 타입에 대해) const T가 와야 하는 곳에, T를 가리키는 포인터를
쓸 수 있습니다. 이 규칙은 포인터 타입이 qualified 부분이 서로 약간
다를 경우에도 쓸 수 있다는 것을 의미하며,
여기에는 한 가지 예외 사항이 있는데, 이 규칙은
계속 재귀적으로(recursively) 적용되지 않고,
단지 top-level에만 적용 된다입니다.
(즉, \TT{const char **}는 const char에
대한 포인터를 가리키는 포인터이므로, 이 예외 사항에 해당되지 않습니다.)
\TT{const char **}가 필요한 곳에 \TT{char **}를 쓸 수 없는 이유는
조금 불명확합니다. \TT{const}가 붙어 있기 때문에, 컴파일러는
여러분이 \TT{const} 값을 변경하지 않는다고 한 약속을 지킬 수 있도록
도와주려 합니다. 그렇기 때문에 \TT{const char *}가 필요한 곳에
\TT{char *} 타입을 쓸 수 있으며, 반대 경우에는 쓸 수 없습니다:
간단한 포인터 타입에 \TT{const}를 붙이는 것은, 프로그램이
매우 안전하게 동작할 수 있도록 도와줍니다. 그러나, 반대로 \TT{const}를
제거하는 것은 때때로 위험할 수 있습니다. 아래처럼 조금 복잡한
대입 연산들을 생각해보기 바랍니다:
\begin{verbatim}
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
\end{verbatim}
세번째 줄에서 우리는 \TT{const char **}가 필요한 곳에, \TT{char **}를
대입했습니다. (컴파일러는 이 부분에서 경고를 발생시킵니다.) 네번째
줄에서, 우리는 \TT{const char *}를 \TT{const char *}가 필요한 곳에
대입했습니다; 이 것은 아무런 문제가 없습니다. 다섯번째 줄에서 우리는
\TT{char *} 포인터가 가리키는 것을 변경시켰습니다. 이 것은 아무런
문제가 없어보이지만, \TT{p1}은 사실 \TT{c}를 가리키고 있고, 이 것은
\TT{const}이기 때문에 문제가 됩니다. 다시 잘 분석하면, 이 것은 네번째
줄에서 \TT{*p2}가 실제로 \TT{p1}을 가리키고 있었던 것이 문제입니다.
\TT{*p2}가 \TT{p1}을 가리키도록 만든 것은 바로 세번째 줄에서 했던
것이고, 이 것은 허용되지 않는 대입 연산이며, 이런 이유 때문에,
허용되지 않습니다.\footnote{C++ 언어는 \TT{const}가 붙은 포인터에
대해 좀 더 복잡한 규칙을 쓰며, 이 규칙은 좀 더 다양한 꼴의 대입을
허용하지만, 이와 같이 \TT{const}가 붙은 오브젝트를 변경하는 것은
막아 줍니다. C++에서도 \TT{const char **}가 올 곳에 \TT{char **}를
대입하는 것은 허용되지 않지만, \TT{const char * const *}가
올 곳에 \TT{char **}를 쓰는 것은 허용됩니다.}
(앞 예제 세번째 줄에서처럼) \TT{const char **}에 \TT{char **}를
대입하는 것은 그 자체가 위험한 것은 아닙니다. 그러나 위에서 \TT{p2}가
약속하고 있는 것, 즉 궁극적으로 가리키고 있는 값을 변경하지 않는다를
깨뜨릴 수 있는 실마리를 제공합니다. 그래도 이러한 연산이 필요하다면,
다시 말해, 가장 최상위 수준이 아닌 곳에서 qualifier가 서로 달라서
대입이 되지 않는 것을 대입시키려면,
직접 캐스트해서 (즉, 이 경우에는 \TT{(const char) **}로) 쓸
수 있습니다.
\R
\cite{ansi} \S\ 3.1.2.6, \S\ 3.3.16.1, \S\ 3.5.3 \\
\cite{c89} \S\ 6.1.2.6, \S\ 6.3.16.1, \S\ 6.5.3 \\
\cite{hs} \S\ 7.9.1 \Page{221--2}
\end{faq}
\begin{faq}
\Q{11.11}
다음과 같은 선언에서:
\begin{verbatim}
typedef char *charp;
const charp p;
\end{verbatim}
왜 \TT{p}가 가리키는 \TT{char}가 \TT{const}가 되지 않고, \TT{p} 자체가
\TT{const}가 되는 것일까요?
\A
Typedef로 치환한 것은 순수하게 textual 치환이 아닙니다.
(이 것은 typedef를 쓰는 한가지 장점이기도 합니다; 질문 \ql{1.13} 참고)
다음과 같은 선언에서:
\begin{verbatim}
const charp p;
\end{verbatim}
\TT{const int i}가 \TT{i}를 \TT{const}로 만드는 것과 같은 원리에서,
\TT{p}는 \TT{const}가 됩니다. \TT{p}에 대한 선언은, 포인터가 관련이
되어있는지 typedef 안까지 쫓아가서 확인하지 않습니다.
\R
\cite{hs} \S\ 4.4.4 \Page{81--2}
\T
아래와 같은 선언이
있다고 가정하고 (질문 \ql{11.9} 참고):
\begin{verbatim}
int * const const_pointer;
\end{verbatim}
\noindent 위에서 \verb+const_pointer+는 \TT{typedef}를 써서 다음과
같이 쓸 수 있습니다:
\begin{verbatim}
typedef int *int_pointer;
const int_pointer const_pointer;
\end{verbatim}
\noindent 이 때, \verb+const_pointer+는 상수 \TT{int}를 가리키는
포인터처럼 보이지만, 실제로는 (상수가 아닌) \TT{int}를 가리키는
const 포인터입니다. 또, 타입 specifier와 타입 qualifier의 순서는
중요하지 않기 때문에 (순서가 바뀔 수 있기 때문에), 다음과 같이
쓸 수도 있습니다:
\begin{verbatim}
int_pointer const const_pointer;
\end{verbatim}
\R
\cite{hs5} \S\ 4.4.4 \page{90}
\end{faq}
\section{Using \TT{main()}}
% from 11.12
Although every C program must by definition supply a function named
\TT{main}, the declaration of \TT{main} is unique because it has two acceptable
argument lists, and the rest of the declaration (in particular, the return
type) is dictated by a factor outside of the program's control, namely, the
startup code that will actually call \TT{main}.
\begin{faq}
\Q{11.12a}
\TT{main()}의 정확한 선언 방법을 알고 싶습니다.
\A
\TT{main()}의 선언은 다음 중에서 골라 써야 합니다:
\begin{verbatim}
int main(void);
int main(int argc, char *argv[]);
\end{verbatim}
\noindent \TT{argv}를, \TT{char **argv}로 선언할 수도 있습니다.
(질문 \ql{6.4}를 참고하기 바랍니다.)
\noindent (물론 이때 `\TT{argv}'와 `\TT{argc}'라는 이름은
얼마든지 바꿀 수 있습니다.) 또 오래된 스타일을 써서 다음과 같이
할 수도 있습니다:
\begin{verbatim}
int main()
int main(argc, argv)
int argc;
char **argv;
\end{verbatim}
질문 \ql{11.12b}부터 \ql{11.15}까지 참고하기 바랍니다.
\R
\cite{c89} \S\ 5.1.2.2.1, \S\ G.5.1 \\
\cite{hs} \S\ 20.1 \page{416} \\
\cite{ctp} \S\ 3.10 \Page{50--51} \\
\cite{c99} \S\ 5.1.2.2.1,
\S\ J.1.1, \S\ J.2.1, \S\ J.3.2.1, \S\ J.5.1 \\
\cite{hs5} \S\ 9.9, \S\ 9.11.4, \S\ 16.5
\T
원래 C 언어에서, 함수의 정의나 변수 선언에서 타입을 (type specifier)
생략했을 때, 디폴트로 \TT{int} 타입이 됩니다. 그러나 이런 식으로
생략하는 것은 그 동안 나쁜 프로그래밍 스타일로 여겨졌으며,
현재 C99 표준에서는 에러입니다.
\cite{hs5} \S\ 4.4.1
\end{faq}
\begin{faq}
\Q{11.12b}
``main returns no value''라는 경고를 피하기 위해,
\TT{main()}을 \TT{void} 타입으로 선언해도 괜찮을까요?
\A
안됩니다. \TT{main()}은 반드시 \TT{int} 타입을 리턴하도록
선언되어야 하며, 인자는 0개 또는 2개이어야 합니다.
종료할 때, \TT{exit()}를 썼는데도 계속 이러한 경고가 발생한다면,
마지막에 쓸데없는 여분의 (redundant) 리턴 문장을 써 주어
경고가 발생하는 것을 막을 수 있습니다. (가능하다면 컴파일러가
제공하는 ``not reached''를 의미하는 지시어(directive)를 써
주어도 됩니다).
단순히 경고를 없애려고 함수를 \TT{void} 타입으로 선언하는 것은
매우 좋지 않습니다; 왜냐하면, 내부적인 함수 호출/리턴 시컨스가
함수를 호출하는 쪽과 (\TT{main()}의 경우, C run-time startup code)
서로 다를 수 있기 때문입니다.
% DOTO: 아래 내용 번역
(Note that this discussion of main() pertains only to "hosted"
implementations; none of it applies to "freestanding"
implementations, which may not even have main(). However,
freestanding implementations are comparatively rare, and if
you're using one, you probably know it. If you've never heard
of the distinction, you're probably using a hosted
implementation, and the above rules apply.)
\R \cite{c89} \S\ 5.1.2.2.1, \S\ G.5.1 \\
\cite{hs} \S\ 20.1 \page{416} \\
\cite{ctp} \S\ 3.10 \Page{50--51}
\end{faq}
\begin{faq}
\Q{11.13}
\TT{main}의 세 번째 인자인 \TT{envp}가 있다고 들었습니다.
\A
세 번째 인자는 자주 쓰이기는 하지만 표준 인자는 아닙니다.
이는 환경(environment) 변수에 접근하기 위한 것으로,
이 목적으로 쓰이는 표준 함수 \TT{getenv()}가 제공되고,
전역 변수로 \TT{environ}이 제공되기 때문에,
이 비표준 세번째 인자를 쓸 이유가 없습니다 (하지만,
전역 변수 \TT{environ}도 비표준이기는 마찬가지입니다).
\R
\cite{c89} \S\ G.5.1 \\
\cite{hs} \S\ 20.1 \Page{416--7}
\T
전역 변수 \TT{environ}은 POSIX.1 표준입니다. (물론 POSIX.1은
C 표준과 다르기 때문에, C 언어 관점에서는 비표준이라 할 수 있습니다.)
\begin{verbatim}
#include <unistd.h>
extern char **environ;
\end{verbatim}
원래, 전통적으로 UNIX 시스템에서는 \TT{main}이 세번째 인자를
받을 수 있게 선언할 수 있었습니다. 즉 다음과 같습니다:
\begin{verbatim}
int main(int argc, char *argv[], char *envp[]);
\end{verbatim}
그러나, 이 것은 (C 표준이 아닌 것은 물론) POSIX.1 표준도
아닙니다. POSIX.1을 따르면, ISO C 표준을 존중하기 위해, \TT{main}의
세번째 인자인 \TT{envp}와 같은 방식으로 동작하는, 전역 변수
\TT{environ}을 써야 한다고 씌여 있습니다.
한 환경 변수의 값을 얻기 위해서는, 표준 함수인 \TT{getenv}를
쓰는 것을 권장합니다. 하지만, 모든 환경 변수의 이름과 값을 얻기 위한
표준 방법은 존재하지 않습니다. 모든 환경 변수의 이름과 값을 꼭 얻어야
겠다면, (C 표준은 아니지만) POSIX.1 표준인 전역 변수 \TT{environ}을
쓸 것을 권장합니다.
질문 \ql{19.33}을 참고하기 바랍니다.
% TODO: 다른 질문과 연관성을 꼭 쓰도록. 특히 Chapter 19와..
% TODO: POSIX.1에 대해서도 다룰 것.
\R
\cite{hs5} \S\ 9.9 \page{304} \\
\cite{sus} environ
\end{faq}
\begin{faq}
\Q{11.14}
\TT{main()}을 \TT{void} 타입으로 선언한다 하더라도, \TT{exit()}
함수를 써서 종료한다면 문제될 게 전혀 없지 않나요?
게다가 제가 쓰고 있는 운영 체제는 프로그램의 종료/리턴 코드를
아예 무시한답니다.
\A
\TT{main()}의 리턴 값이 쓰이냐, 쓰이지 않느냐는 중요한 문제가
아닙니다; 문제는 \TT{main()}을 \TT{void} 타입으로 선언함으로
인하여, \TT{main()}을 호출하는 부분이 (런-타임 시작(startup) 코드)
\TT{main()}을 제대로 호출하지 못할 수 있다는 것입니다
(이는 calling convension 문제입니다; 질문 \ql{11.12b}를 참고하기
바랍니다).
Borland C++ 4.5에서 \TT{void main()}을 썼을 때, 프로그램이
망가질 수 있다는 것이 이미 보고되었습니다.
그리고 어떤 컴파일러들은 (DEC C V4.1과 gcc) \TT{main}을 \TT{void}
타입으로 선언했을 때, 경고를 발생합니다.
여러분의 운영 체제가 종료 상태(exit status)를 무시할 수도 있고,
\TT{void main()}이 동작할 수도 있지만, 이는 이식성이 없을 뿐만
아니라, 올바른 것도 아닙니다.
여러 시스템에서 \TT{void main()}으로 써도 동작한다는 것은 사실입니다.
만약 이식성을 전혀 고려할 생각이 없고, 이 방식이 더 편하다고 생각하면,
아무도 말릴 사람은 없습니다.
\T
C 표준은, 질문 \ql{11.12a}에 나온 꼴의 \TT{main} 함수를 지원할 것을,
컴파일러에게 요구합니다. 또한 컴파일러는 C 표준에 나와 있지 않는 형태의
\TT{main}을 제공하는 것에는 관여하지 않습니다. 그러나, 다른 비표준
형태를 쓰는 것은 (표준 관점에서 봤을 때) `undefined behavior'를
낳습니다.
\end{faq}
\begin{faq}
\Q{11.15}
제가 보고 있는 책 ``C Programming for the Compleat Idiot''에서는
항상 \TT{void main()}을 사용합니다.
\A
아마도 그 책의 저자는 자신도 그 범주(complete idiot)에
계산한 모양입니다.
많은 책들이 \TT{void main()}을 쓰고 있지만 이는 잘못된 것입니다.
\end{faq}
\begin{faq}
\Q{11.16}
\TT{main()}에서 어떤 값을 리턴하는 것과 \TT{exit()}를 쓰는 것과
완전히 같나요?
\A
그렇다고, 또는 그렇지 않다고 할 수 있습니다.
C 표준에서는 완전히 같다고 언급하고 있지만, 어떤 오래된 시스템에서는
(특히 C 표준을 준수하지 않는), (리턴하는 것과 \TT{exit}를 쓰는 것 중)
어느 한 쪽이 정상적으로 동작하지 않을 수 있습니다.
\TT{main}에 local 데이터가 `cleanup' 과정에서 필요할 경우,
\TT{main}에서 리턴하는 방법은 제대로 동작하지 않을 수 있습니다;
질문 \ql{16.4}를 참고하기 바랍니다.
그리고 아주 오래된 (표준을 지원하지 않는) 몇몇 시스템에서는
두 가지 형식 중 하나가 제대로 동작하지 않을 수 있습니다.
% TODO: 다음 문장 번역
% (Finally, the two forms are obviously not equivalent
% in a recursive call to main().)
(마지막으로, 이 두가지 형태는 \TT{main()}을 재귀적으로 호출할 경우,
다른 코드를 생성합니다.)
\R \cite{kr2} \S\ 7.6 \Page{163--4} \\
\cite{c89} \S\ 5.1.2.2.3
\T
C++ 언어와는 달리, C 언어 표준에서는 \TT{main()}이 재귀적으로
(즉, recursive하게, \TT{main}이 다시 \TT{main}을 부르는 경우)
호출되는 것을 막지
않았습니다.\footnote{C++ 언어에서는 \TT{main}을 재귀적으로 부를 수
없으며, \TT{main}의 주소를 얻는 것도 금지되어 있습니다.}
즉, 원한다면 \TT{main}에서 다시 \TT{main}을 부를 수 있습니다.
그러나, IOCCC에 출품할 것이 아니라면, 그런 코드를 만들 이유가
없습니다. (IOCCC에 대한 것은 질문 \ql{20.36}을 참고하기 바랍니다.)
C99 표준에 따르면, (표준에 부합하는 형태, 즉 \TT{int}를 리턴하는)
\TT{main}에서 어떤 값을 \TT{return} 하는 것은,
\TT{exit} 함수를 그 값으로 부르는 것과 같다고 씌여 있습니다.
그리고 이 효과가 일어나는 것은, 프로그램 시작점으로 쓰인 \TT{main}에서만
일어납니다. 즉, 재귀적으로 불려진 \TT{main}에서 \TT{return}한다고
\TT{exit}가 자동으로 호출되지 않습니다.
또한 \TT{exit}나 \TT{return} 문장 없이 \TT{main}이 끝나버리면,
\TT{return 0}을 쓴 것과 같은 효과를 얻을 수 있다고 씌여 있습니다.
(이 것은 C99에 새로 추가된 내용입니다. 그 전 표준인 ANSI, C89 등에서는
해당되지 않습니다.)
\TT{return}하는 것과 \TT{exit}를 부르는 것에 미세한 차이가 있을 수
있는데, 만약 \TT{atexit}로 exit handler를 등록시켜 놓았고, 그 handler가
\TT{main}에서 만든 어떤 automatic (static이 아닌) 변수에 접근한다면,
\TT{return}하는 것은 이 변수에 접근할 수 없습니다.
즉, \TT{return}을 써서 자동으로 \TT{exit}를 부르게 하는 것은, 이미
\TT{main} 함수의 블럭을 벗어났기 때문에, \TT{main}에서 선언한 automatic
변수는 존재하지 않습니다.
\R
\cite{c99} \S\ 5.1.2.2.3, \S\ 7.19.3.5
\end{faq}
\section{Preprocessor Features}
% from 11.17
ANSI C introduces a few new features into the C preprocessor, including
the ``stringizing'' and ``token pasting'' operators and the \verb+#pragma+
directive.
\begin{faq}
\Q{11.17} % COMPLETE
ANSI ``stringizing'' 전처리기 연산자인 \verb+#+를 써서 심볼릭
상수의 값을 문자열에 집어 넣으려고 합니다, 그런데,
그 결과, 상수의 값이 들어가는 대신, 상수의 이름이 들어가는군요.
\A
\verb+#+의 정의에 따르면, 이 것은 매크로 인자를
(인자가 또 다른 매크로 이름이더라도 더 이상 확장하지 않고)
바로 문자열로 만듭니다.
매크로가 원래 지닌 뜻으로 확장되길 원한다면 다음과 갈이
두 단계를 거쳐서 쓸 수 있습니다:
\begin{verbatim}
#define Str(x) #x
#define Xstr(x) Str(x)
#define OP plus
char *opname = Xstr(OP);
\end{verbatim}
이 코드는 \TT{opname}을 ``OP''로 설정하지 않고, ``plus''로
설정합니다. (즉, \TT{Xstr()} 매크로가 인자를 확장하고 \TT{Str()}
매크로가 문자열로 만듭니다.)
비슷한 상황이 ``token-pasting'' 연산자인 \verb+##+를 쓸 때,
두 매크로의 값을 연결하려 할 때 발생할 수 있습니다.
\verb+#+나 \verb+##+는 일반 소스 코드에서는 쓰일 수 없으며,
다만 매크로 정의 부분에서만 쓸 수 있는 연산인 것을 꼭 기억하기
바랍니다.
\R
\cite{ansi} \S\ 3.8.3.2, \S\ 3.8.3.5 example \\
\cite{c89} \S\ 6.8.3.2, \S\ 6.8.3.5.
\end{faq}
\begin{faq}
\Q{11.18} % 11.18 COMPLETE
메시지 ``warning: macro replacement within a string literal''은
무슨 뜻이죠?
\A:
ANSI 이전의 어떤 컴파일러/전처리기는 매크로 정의를 다음과 같이
정의할 경우:
\begin{verbatim}
#define TRACE(var, fmt) printf("TRACE: var = fmt\n", var)
\end{verbatim}
\noindent 다음과 같은 식으로 호출하게 되면:
\begin{verbatim}
TRACE(i, %d);
\end{verbatim}
\noindent 다음과 같이 확장하게 됩니다:
\begin{verbatim}
printf("TRACE: i = %d\n", i);
\end{verbatim}
즉, 매크로 인자로 나온 이름이 문자열 안에 있는 경우라도
확장시켜 버립니다. (물론 이러한 버그가 위와 같이 유용하게 쓰일 수도
있지만, 이 것은 대개 초창기 컴파일러를 만들 때 잘 못 만든 것입니다.)
이러한 식의 매크로 확장은 K\&R에 언급된 것도 아니며, 표준 C 언어에서
언급된 것도 아닙니다. (매우 위험한 방법이며, 코드가 어려워집니다.
질문 \ql{10.22}를 참고 바랍니다.)
매크로 인자 자체가 문자열이 되기를 원한다면
전처리기 연산자인 \verb+#+를 쓰거나, 문자열 연결 (concatenation) 기능을
쓰면 됩니다 (이는 ANSI 표준의 새로운 기능입니다.):
\begin{verbatim}
#define TRACE(var, fmt) \
printf("TRACE: " #var " = " #fmt "\n", var)
\end{verbatim}
질문 \ql{11.17}을 참고하기 바랍니다.
\R
\cite{hs} \S\ 3.3.8 \page{51}
\end{faq}
\begin{faq}
\Q{11.19}
\verb+#ifdef+를 써서 컴파일하지 말라고 한 곳에서 매우 이상한
구문(syntax) 에러가 납니다.
\A
ANSI C에서, \verb+#if+, \verb+#ifdef+, \verb+#ifndef+에 쓴 텍스트는
전처리기가 처리할 수 있는 유효한 것이어야 (valid preprocssing
token) 합니다.
즉, C 언어에서처럼 \verb+"+나 \verb+'+는 각각이 쌍을 이루어서
나와야 하며, 이처럼 둘러싼 문자열의 안에 newline 문자가 나와서는
안되며, 주석이 끝나지 않고 열려 있어서도 안됩니다.
서로 다른 따옴표가 엇갈려서 있어도 안됩니다.
(특히, 영어의 생략형(contracted word)에
쓰이는, 역 따옴표(apostophe, \verb+`+)는
문자 상수의 시작처럼 보일 수 있다는 것에 주의하기 바랍니다.)
따라서 긴 주석이나 pseudo code를 쓰는 것이 목적이라면
\verb+#ifdef+를 써서 빼라고 지정을 했더라도, 공식적(offical)인
주석(comment)인 \verb+/* ... */+을 써야 합니다.
\R
\cite{c89} \S\ 5.1.1.2, \S\ 6.1 \\
\cite{hs} \S\ 3.2 \page{40}
\T
C99 표준에 따라서, C++ 언어에서 쓰는 것처럼 \TT{//}로 시작하는
주석도 쓸 수 있습니다.
\end{faq}
\begin{faq}
\Q{11.20} % 11.20 COMPLETE
\verb+#pragma+는 어디에 쓰나요?
\A
\verb+#pragma+는 모든 종류의 (이식성이 떨어지는) 모든 구현 방법에
따른 기능을 제어하고, 확장 기능을 제공합니다; 여기에는
소스 리스팅 제어, 구조체 압축(packing), 그리고
경고 출력 수준(\TT{lint}의
오래된 주석 형태인 \verb+/* NOTREACHED */+와 같이) 등이
포함됩니다.
\R
\cite{ansi} \S\ 3.8.6 \\
\cite{c89} \S\ 6.8.6 \\
\cite{hs} \S\ 3.7 \page{61}
\T
예전에는 \verb+#pragma+ 뒤에 나오는 것들(간단히 pragma라고 부르기도
함)은 모두 시스템에 의존적인 사항이었으나, C99에서는 몇가지 표준
pragma를 만들었습니다. 표준 pragma는 \verb+#pragma+ 바로 다음에
\TT{STD}가 나오며, 그 뒤에 나오는 정보는 매크로 확장이 되지 않습니다.
\begin{verbatim}
#pragma STD FENV_ACCESS ON
#pragma STD FP_CONTRACT ON
#pragma STD CX_LIMITEED_RANGE ON
\end{verbatim}
표준 C 언어에서 공식적으로 제공하는 pragma는 위 세 가지이며, 위에서
\TT{ON} 대신에 \TT{OFF}나 \TT{DEFAULT}를 쓸 수 있습니다.
\R
\cite{hs5} \S\ 3.7 \Page{67--69}
% TOOD: c99 reference!
\end{faq}
\begin{faq}
\Q{11.21}
``\verb+#pragma once+''가 의미하는 것이 뭐죠?
\A
이는 어떤 전처리기들이 제공하는 기능으로 헤더 파일이 단 한번씩만
포함되도록 하는, 질문 \ql{10.7}에 소개된 \verb+#ifndef+ 트릭과 같은 역할을