검색결과 리스트
Programming에 해당되는 글 119건
- 2010.09.18 ARM C Compiler
- 2010.08.21 HTTP and WWW
- 2010.08.21 프록시 서버( proxy server )
- 2010.07.31 [C++] this 포인터 사용하기
- 2010.07.31 [C++] 참조 변수 1
- 2010.07.31 [C++] 참조 반환
- 2010.07.21 [C++] 클래스 I
- 2010.07.16 [C++] C++상에서 발생하는 name mangling에 관한 내용
- 2010.07.07 [makefile]commands commence before first target 에러
- 2010.06.14 [C++] Errors : cannot allocate an object of abstract type '???'
1SEP
글
ARM C Compiler
Programming
2010. 9. 18. 16:48
The ARM C Compiler
armcc
SYNOPSIS
armcc [options] sourcefile ...
DESCRIPTION
The ARM C compiler is a mature, industrial-strength com- piler, based on Codemist Ltd's multi-target, multi- language compiler suite (also known as the Norcroft C com- piler). By default the ARM C compiler compiles ANSI C as defined by American National Standard for Information Systems - Programming Language C, X3J11/90-013, Feb 14, 1990. The ARM C compiler also has a pcc mode, which accepts the dialect of C used by Berkeley Unix. In this mode the com- piler has been used to build a complete ARM-based Unix system (the RISCiX system). For more background about the ARM C Compiler, and for rec- ommended reading for C programmers, as well as full tech- nical information on the ARM C Compiler see "The ARM C Compiler" of the Reference Manual.
OPTIONS
By default, the C compiler looks for source files, and creates object, assembler and listing files, in the cur- rent directory. Many aspects of the compiler's operation can be controlled via command-line options. All options are prefixed by a minus sign. There are two classes of option: keywords and flags. Key- words are recognised in upper case or lower case. A flag is a single letter, the case of which is sometimes impor- tant to the ARM C compiler. Because some systems (such as Unix) are very case sensitive, the case of flags is most important when you are building portable makefiles. By using the conventions common to many C compilers, you can move a makefile between different environments at minimum cost. Keyword Options -help Give a summary of the compiler's command line options. -pcc Compile (BSD 4.2) portable C compiler C. This dialect is based on the original Kernighan and Ritchie (K&R) definition of C, and is the one used on Unix systems. The -pcc keyword alters the lan- guage accepted by the compiler, but the built-in ANSI headers are still used. For more details on this, see section "PCC Compatibility Mode" of the Be extra strict about enforcing conformance to the ANSI standard or to pcc conventions (e.g. prohibit the volatile qualifier in -pcc mode). -list Create a listing file. This consists of lines of source interleaved with error and warning messages. Finer control over the contents of this file may be obtained using the -f flag (see"Controlling Addi- tional Compiler Features" starting on page13). -littleend or -li Compile code for an ARM operating with little- endian (least significant byte has lowest address) memory. -bigend or -bi Compile code for an ARM operating with big-endian (most significant byte has lowest address) memory. By default, the ARM C compiler compiles code with the same byte order as the host system. However, most releases of the ARM C compiler, for most hosts, allow this default to be configured when the compiler is installed, so it is not usually neces- sary to use either of these options (see "The ARM Tool Reconfiguration Utility (reconfig)" for more information). -apcs [3]qualifiers Specify which variant of the ARM Procedure Call Standard is to be used by the compiler. The default is set up when armcc is configured, and for ease of use can be reconfigured using the reconfig tool - see "The ARM Tool Reconfiguration Utility (reconfig)" for details. Alternatively the default can be changed by use of this keyword option. At least one qualifier must be present, and there must be no space between qualifiers. The following qualifiers are permitted: /26[bit] 26 bit APCS variant. /32[bit] 32 bit APCS variant. /reent[rant] Reentrant APCS variant. /nonreent[rant] Non reentrant APCS variant. Software stack checking APCS variant. /noswst[ackcheck] No software stack checking APCS vari- ant. /fpe2 Floating point emulator 2 compatibil- ity. /fpe3 Floating point emulator 3 compatibil- ity. /fpr[egargs] F.P. arguments passed in FP. registers. /nofpr[egargs] F.P. arguments are not passed in F.P. registers For details of the various APCS variants see "ARM Procedure Call Standard" starting on page 38 of the Technical Specifications. Flag Options The flag options are listed below. Some of these are fol- lowed by an argument. Whenever this is the case, the ARM C compiler allows white space to be inserted between the flag letter and the argument. However, this is not always true of other C compilers, so in the following subsections we only list the form that would be acceptable to a Unix C compiler. Similarly, we only use the case of the letter that would be accepted by a Unix C compiler. The descrip- tions are divided into several subsections, so that flags controlling related aspects of the compiler's operation are grouped together. Controlling the linker -c Do not perform the link step. This merely compiles the source program(s), leaving the object file(s) in the current directory (or as directed by the -o flag). This is different from the -C option described in"Preprocessor Flags" starting on page9. Preprocessor Flags -Idirectory-name This adds the specified directory to the list of places which are searched for included files (after the in-memory or source file directory, according to the type of include file). The directories are searched in the order in which they are given by multiple -I options. See "Included Files" of the Reference Manual for full details. directory-list is a comma separated list of search directories. This option adds the list of directo- ries specified to the end of the search path (ie. after all directories specified by -I options), but otherwise in the same way as -I. However, it also has the side effect of stopping system include files being searched for in the in- memory filing system before all other searches. Instead the in-memory filing system is searched for system include files only after all other searches have failed. Note that the in-memory filing system can be speci- fied in -I and -j options by :mem. This is an ARM-specific flag and is not portable to other C systems. There may be at most one -j option on a command line. See "Included Files" starting on page61 of the Reference Manual for full details. -E If this flag is specified, only the preprocessor phase of the compiler is executed. The output from the preprocessor is sent to the standard output stream. It can be redirected to a file using the stream redirection notations common to Unix and MS- DOS (e.g. armcc -E something.c > rawc By default, comments are stripped from the output, (but see -C flag, below). -C When used in conjunction with -E above, -C retains comments in preprocessor output. It is different from the -c flag, which is used to suppress the link operation. -M If this flag is specified, only the preprocessor phase of the compiler is executed (as with armcc -E) but the only output produced is a list, on the standard output stream, of makefile dependency lines suitable for use by a make utility. This can be redirected to a file using standard Unix/MS-DOS notation. For example: armcc -M xxx.c >> Makefile. -Dsymbol=value Define symbol as a preprocessor macro, as if by a line #define symbol value at the head of the source file. Define symbol as a preprocessor macro, as if by a line #define symbol at t he head of the source file. -Usymbol Undefine symbol, as if by a line #undef symbol at the head of the source file. Controlling Code Generation -gLetters This flag is used to specify that debugging tables for use by the ARM Source Level Debugger (armsd) should be generated. It is followed by an optional set of letters which specify the level of informa- tion required. If no letters are present then all the information possible is generated. However, the tables can occupy large amounts of memory so it is sometimes useful to limit what is included as fol- lows. -gf Generate information on functions and top-level variables (those declared outside of functions) only. -gl Generate information describing each line in the source file(s). -gv Generate information describing all variables. The last three modifiers may be specified in any combination, e.g. -gfv. -o file The argument to the -o flag gives the name of the file which will hold the final output of the compi- lation step. In conjunction with -c, it gives the name of the object file; in conjunction with -S, it gives the name of the assembly language file. Oth- erwise, it names the final output of the link step. -Ospace Perform optimisations to reduce image size at the expense of increased execution time. -Otime Perform optimisations to reduce execution time at the expense of a larger image. -p and -px The -p flag makes the compiler generate code to count the number of times each function is exe- cuted. If -px is given, the compiler also generates cific to ARM C, though -p is widely used by other C systems to request profiling. At the end of a program run, the counts can be printed to stderr by calling the ARM C library function _mapstore(), or to a named file of your choice by calling _fmapstore("filename"). The printed results are lists of lineno, count pairs. The lineno value is the number of a line in your source code, and count is the number of times it was executed. Note that lineno is ambiguous: it may refer to a line in an included file, but this is rare and usually causes no confusion. Provided that the program wasn't compiled with the -ff option, blocks of counts will be interspersed with function names. In the simplest case the out- put is reduced to a list of line pairs like: function-name lineno: count where count is the number of times the function was executed. If -px was used, the lineno values within each function relate to the start of each basic block. Sometimes, a statement (such as a for statement) may generate more than one basic block, so there can be two different counts for the same line. Profiled programs run slowly. For example, when compiled -p, Dhrystone 1.1 runs at about 5/8 speed; when compiled -px it runs at only about 3/8 speed. There is no direct way to relate these execution counts to the amount, or proportion, of execution time spent in each section of code. Nor is there yet any tool for annotating a source listing with profile counts. Future releases of ARM C may address these issues. -S If the -S flag is specified, no object code is gen- erated but a listing of the equivalent assembly language is written to a file. By default, the file is call ed name.s in the current directory (where name.c is the name of the source file stripped of any leading directory names). The default can be overridden using the -o flag (see above). -via file it. This is intended mainly for hostings (such as the PC) where command line length is severely lim- ited. Controlling Warning Messages -WLetters The -W option controls the suppression of warning messages. Usually the compiler is very free with its warnings, as these tend to indicate potential portability problems or other hazards. However, too many warning messages can be a nuisance in the early stages of porting a program written in old- style C, so warnings can disabled. -W If no modifier letters are given, then all warnings are suppressed. If one or more letters follow the flag, then only the warnings controlled by those letters are suppressed. -Wa Give no "Use of = in a condition context" warning. This is given when the compiler encounters a state- ment such as: if (a = b) {... where it is quite possible that the author really did intend if ((a = b) != 0) {... and also plausible that the author intended if (a == b) {... but missed a key stroke. In new code, the deliber- ate use of the needlessly dangerous if (a = b) ..., should be avoided. This warning is also suppressed in -pcc mode. -Wd Give no "Deprecated declaration foo() - give arg types" message, given when a declaration without argument types is encountered in ANSI mode (the warning is suppressed anyway in -pcc mode). In ANSI C, declarations like this are deprecated and a future version of the C standard may ban them. They are already illegal in C++. However, it is sometimes useful to suppress this warning when porting old code. -Wf Give no "Inventing extern int foo()" message, which may be useful when compiling old-style C in ANSI warning is issued when the compiler detects the implicit narrowing of a long expression in an int or char context, or the implicit narrowing of a floating point expression in an integer or narrower floating point context. Such implicit narrowings are almost always a source of problems when moving code developed using a fully 32-bit system (such as ARM C) to a C system in which ints occupy 16 bits and longs 32 bits (as is common on the IBM PC, Apple Macintosh, etc.). -Wv Give no "Implicit return in non-void context" warn- ing. This is most often caused by a return from a function which was assumed to return int (because no other type was specified) but is in fact being used as a void function. Because the practice is widespread in old-style C, the warning is sup- pressed in -pcc mode. Controlling Additional Compiler Features -zpLetterDigit This flag can be used to emulate #pragma direc- tives. The letter and digit which follow it are the same characters that would follow the '-' of a #pragma directive. See the section "Pragma Direc- tives" of the Reference Manual for details. -zrNumber This flag allows the size of (most) LDMs and (all) STMs to be controlled between the limits of 3 and 16 registers transferred. This can be used to help control interrupt latency where this is critical. -fLetters The -f flag described in this section controls a variety of compiler features, including certain checks more rigorous than usual. Like the -W flag it is followed by a string of modifier letters. At least one letter is required, though several may be given at once, for example, -ffah. -fa Check for certain types of data flow anomalies. The compiler performs data flow analysis as part of code generation. The checks enabled by this option indicate when an automatic variable could have been used before it has been assigned a value. The check is pessimistic and will sometimes report an anomaly where there is none, especially in code like the following: int initialised = 0, value; ... value = ...; initialised = 1; Here, we know that value is read if, and only if, initialised has been set (but in general, the argu- ment may be delicate). As this is a semantic deduc- tion, not a data flow implication, -fa will report an anomaly. In general, it is useful to check all code using -fa at some stage during its development. -fc Enable the "limited pcc" option, designed to sup- port the use of pcc-style header files in an other- wise strict ANSI mode (e.g. when using libraries of functions implemented in old-style C from an appli- cation written in ANSI C). This allows characters after #else and #endif preprocessor directives (which are ignored). The "limited pcc" option also supports system pro- gramming in ANSI mode by suppressing warnings about explicit casts of integers to function pointers, and permitting the dollar character in identifiers, (linker-generated symbols often contain "$$" and all external symbols containing "$$" are reserved to the linker). -fe Check that external names used within the file are still unique when reduced to six case-insensitive characters. Some (now very old) linkers support as few as six significant characters in external sym- bol names. This can cause problems with clashes if a system uses two names such as getExpr1 and get- Expr2, which are only unique in the eighth charac- ter. The check can only be made within a single compilation unit (source file) so cannot catch all such problems. ARM C allows external names of up to 256 characters, so this is strictly a portability aid. -ff Do not embed function names in the code area. The compiler does this to make the output produced by the stack backtrace run time support function and the _mapstore() function (see "-p and -px") more readable. Removing the names from the compiler itself makes the code slightly smaller (about 5%). In general it is not useful to specify -ff with -p. -fh Check that all external objects are declared before use and that all file scoped static objects are used. If external objects are only declared in included header files (never in-line in a C source -fi In the listing file (see "-list") list the lines from any files included with directives of the form: #include file -fj As above, but for files included by lines of the form: #include <file> -fk Use K&R search rules for locating included files (the current place is defined by the original source file and is not stacked; see section "The Search Path" starting on page61 of the Reference Manual for details). -fm Report on preprocessor symbols defined but not used during the compilation. -fp Report on explicit casts of integers into pointers, e.g. char *cp = (char *) anInteger; (Implicit casts are reported anyway, unless sup- pressed by the -Wc option). -fu By default, if -list is specified, the compiler lists the source text as seen by the compiler after preprocessing. If -fu is specified then the unex- panded source text, as written by the user, is listed. For example, consider the line: p = NULL; /* assume NULL defined to be (0) */ By default, this will be listed as p = (0); with -fu specified, as p = NULL;. -fv Report on all unused declarations, including those from standard headers. -fw Allow string literals to be writeable, as expected by some Unix code, by allocating them in the pro- gram's data area rather than the notionally read- only code area. Note that this also prevents the re-use by the compiler of a multiple, occurring string literal. When writing high-quality production software, you diagnostics produced can be annoying in the earlier stages).
SEE ALSO
armlink(1), reconfig(1), armsd(1) Reference Manual, Technical Specifications
출처 : http://www.cl.cam.ac.uk/teaching/1998/CompDesn/fromlecturer/htmlman/armcc.html
'Programming' 카테고리의 다른 글
[makefile]commands commence before first target 에러 (0) | 2010.07.07 |
---|---|
세마포어( Semaphore ) (1) | 2010.05.31 |
Event-driven programming (0) | 2010.05.31 |
undefined reference (0) | 2010.03.26 |
XML 이란? (0) | 2010.03.26 |
2AUG
글
HTTP and WWW
Programming/Network
2010. 8. 21. 10:30
HTTP와 WWW, 인터넷의 비약적인 발전을 일으킨 놈들이다.
기본적으로 서버와 클라이언트의 구조로 되어있다. 클라이언트( PC, Mobile Phone etc ) 가 서버에 요청을 하면 서버는 해당 웹페이지를 클라이언트에 전송해 주는 구조이다. request / response 라는 기본 개념에서 시작되었다. 그리고 각 웹페이지는 각 사이트(서버)에 존재를 하고, 우리는 이를 www 를 이용해서 각기 다른 host 에 요청을 하고, 원하는 웹페이지를 받는 것이다.
이 웹페이지를 보여주기 위해서, 해석하고 표현을 해주는 도구가 필요한데 이것이 바로 브라우저이다. 유명 브라우저에는 인터넷 익스프로러, 크롬, 파이어 폭스 등이 있다. 이러한 브라우저는 보통 제어기( controller ), 클라이언트 프로토콜 및 해석기( interpreter ) 의 세부분으로 나뉜다. 제어기는 키보드/마우스로부터 입력을 받아 클라이언트 프로그램을 사용하여 문서를 액세스 한다. 문서가 액세스 되고 난 뒤에는 해석기 중 하나를 사용하여 문서를 화면에 표시한다.
클라이언트 프로토콜은 FTP, HTTP 중에 하나가 될 수 있고, 해석기는 문서의 유형에 따라 HTML, Java or JavaScript 가 될 수 있다.
웹페이지를 엑세스 하기 위해서 URL ( Uniform Resource Locator ) 을 입력하는데, 이는 인터넷에서 어떤 종류의 정보든 지정할 수 있는 표준이다. 표준은 아래와 같다.
간단히 설명하자면
Protocol : FTP, HTTP
Host : 정보가 위치하고 있는 컴퓨터이다.
Port : URL 은 선택적으로 port 번호를 포함할 수 있다. 이는 콜론 으루 구분.
Path : 정보가 위치하고 있는 파일의 경로 이름이다.
쿠키
인터넷 웹사이트의 방문기록을 남겨 사용자와 웹사이트 사이를 매개해 주는 정보이다.
고객이 특정 홈페이지를 접속할 때 생성되는 정보를 담은 임시파일이며, 애초에 인터넷 사용자들의 홈페이지 접속을 위해 만들어졌다. 특정 사이트를 처음 방문하면 아이디와 비밀번호를 기록한 쿠키가 만들어지고 다음에 접속했을 때 절차 없이 사이트에 빠르게 연결 할 수 있다.
쿠키는 사용하는 웹브라우저가 자동으로 만들기도 하고 갱신하기도 하며, 웹사이트로 기록을 전달하기도 한다. 이용자가 인터넷에서 어떤 내용을 봤는지 어떤 상품을 봤는지 모든 정보가 기록이 된다. 따라서 이에 따른 보안 문제가 발생할 수 도 있다.
이러한 쿠키의 생성과 저장에 대해서 알아보겠자.
기본적으로 서버와 클라이언트의 구조로 되어있다. 클라이언트( PC, Mobile Phone etc ) 가 서버에 요청을 하면 서버는 해당 웹페이지를 클라이언트에 전송해 주는 구조이다. request / response 라는 기본 개념에서 시작되었다. 그리고 각 웹페이지는 각 사이트(서버)에 존재를 하고, 우리는 이를 www 를 이용해서 각기 다른 host 에 요청을 하고, 원하는 웹페이지를 받는 것이다.
이 웹페이지를 보여주기 위해서, 해석하고 표현을 해주는 도구가 필요한데 이것이 바로 브라우저이다. 유명 브라우저에는 인터넷 익스프로러, 크롬, 파이어 폭스 등이 있다. 이러한 브라우저는 보통 제어기( controller ), 클라이언트 프로토콜 및 해석기( interpreter ) 의 세부분으로 나뉜다. 제어기는 키보드/마우스로부터 입력을 받아 클라이언트 프로그램을 사용하여 문서를 액세스 한다. 문서가 액세스 되고 난 뒤에는 해석기 중 하나를 사용하여 문서를 화면에 표시한다.
클라이언트 프로토콜은 FTP, HTTP 중에 하나가 될 수 있고, 해석기는 문서의 유형에 따라 HTML, Java or JavaScript 가 될 수 있다.
웹페이지를 엑세스 하기 위해서 URL ( Uniform Resource Locator ) 을 입력하는데, 이는 인터넷에서 어떤 종류의 정보든 지정할 수 있는 표준이다. 표준은 아래와 같다.
Protocol : // | Host : | Port / | Path |
간단히 설명하자면
Protocol : FTP, HTTP
Host : 정보가 위치하고 있는 컴퓨터이다.
Port : URL 은 선택적으로 port 번호를 포함할 수 있다. 이는 콜론 으루 구분.
Path : 정보가 위치하고 있는 파일의 경로 이름이다.
쿠키
인터넷 웹사이트의 방문기록을 남겨 사용자와 웹사이트 사이를 매개해 주는 정보이다.
고객이 특정 홈페이지를 접속할 때 생성되는 정보를 담은 임시파일이며, 애초에 인터넷 사용자들의 홈페이지 접속을 위해 만들어졌다. 특정 사이트를 처음 방문하면 아이디와 비밀번호를 기록한 쿠키가 만들어지고 다음에 접속했을 때 절차 없이 사이트에 빠르게 연결 할 수 있다.
쿠키는 사용하는 웹브라우저가 자동으로 만들기도 하고 갱신하기도 하며, 웹사이트로 기록을 전달하기도 한다. 이용자가 인터넷에서 어떤 내용을 봤는지 어떤 상품을 봤는지 모든 정보가 기록이 된다. 따라서 이에 따른 보안 문제가 발생할 수 도 있다.
이러한 쿠키의 생성과 저장에 대해서 알아보겠자.
'Programming > Network' 카테고리의 다른 글
프록시 서버( proxy server ) (0) | 2010.08.21 |
---|---|
HTTP Method (0) | 2010.06.06 |
Post/Redirect/Get (1) | 2010.05.31 |
트랜잭션 [ transaction ] 이란? (0) | 2010.05.27 |
세션 [ session ] 이란? (0) | 2010.05.27 |
2AUG
글
프록시 서버( proxy server )
Programming/Network
2010. 8. 21. 09:47
네트워크에서 프록시, 핸드폰에 wifi 를 쓸때도 프록시.. 여기저기서 프록시 라는 말이 자주 나온다. 그런데 정작 프록시가 뭐하는 건지 모르겠어서 마침내 찾아보게 되었다. ( -_-; 이놈의 게으름병..)
책을 보면 HTTP 는 프록시 서버를 지원한다고 한다. 즉.. 프록시는 서버를 뜻하는 것이었다. 프록시 서버는 최신 요청에 대한 응답들의 복사본을 가지고 있는 컴퓨터 이다. HTTP 클라이언트는 프록시 서버로 요청을 보내고, 프록시 서버는 캐시(cache)를 검사를 하는데, 이때 해당 응답이 서버에 있게 되면 해당 응답을 보내주고, 그렇지 않으면 적절한 서버로 요청을 보내고, 프록시 서버에 돌아온 응답을 클라이언트에게 보내주게 된다. 그리고, 다른 클라이언트의 요청에 대비해 프록시 서버에 응답이 저장된다. 이렇게, 프록시 서버는 컴퓨터의 캐시와 같은 존재로써, 서버의 부하를 줄이고, 트래픽을 감소하고 지연을 개선하는 목적으로 운영이 된다. 이러한 프록시 서버를 사용하기 위해서는 클라이언트가 대상 서버 대신에 프록시를 액세스 하도록 설정 되어 있어야 한다. 핸드폰에 WIFI 를 설정할 때도 보면, proxy 서버를 설정하는 부분이 옵션으로 들어가 있는 것을 볼 수 있을 것이다.
'Programming > Network' 카테고리의 다른 글
HTTP and WWW (0) | 2010.08.21 |
---|---|
HTTP Method (0) | 2010.06.06 |
Post/Redirect/Get (1) | 2010.05.31 |
트랜잭션 [ transaction ] 이란? (0) | 2010.05.27 |
세션 [ session ] 이란? (0) | 2010.05.27 |
3JUL
글
[C++] this 포인터 사용하기
Programming/C++ Language
2010. 7. 31. 18:56
연속적인 함수 호출을 위해 this 포인터를 사용해 보도록 하자.
SetHour, SetMinute, SetSecond 라는 함수가 있다고 했을 때, 3번의 각각의 호출이 필요하다.
이때, this 포인터를 반환하는 즉, this 참조 반환을 이용하면 연속적으로 호출이 가능하다.
아래의 예문을 살펴보자.
CTimes& CTimes::SetHour(int nHour)
{
hour = nHour;
return *this;
}
CTimes& CTimes::SetMinute( int m )
{
minute = m;
return *this;
}
CTimes& CTimes::SetSecond( int s )
{
second = s;
return *this;
}
위와 같이 Set 함수에 *this 를 반환을 하게 되면, 호출 하는 쪽에서 *this를 호출하여 연속적으로 아래와 같이 호출 할 수 있게 된다.
특별히 성능이 좋아진다거나 그런 것은 없지만, 이를 알고 있다면 코드가 간단해서 보기 쉽지 않을까 생각한다. 앞으로 잘 이용하면 좋은 문법이 될 것 같다.
SetHour, SetMinute, SetSecond 라는 함수가 있다고 했을 때, 3번의 각각의 호출이 필요하다.
이때, this 포인터를 반환하는 즉, this 참조 반환을 이용하면 연속적으로 호출이 가능하다.
아래의 예문을 살펴보자.
CTimes& CTimes::SetHour(int nHour)
{
hour = nHour;
return *this;
}
CTimes& CTimes::SetMinute( int m )
{
minute = m;
return *this;
}
CTimes& CTimes::SetSecond( int s )
{
second = s;
return *this;
}
위와 같이 Set 함수에 *this 를 반환을 하게 되면, 호출 하는 쪽에서 *this를 호출하여 연속적으로 아래와 같이 호출 할 수 있게 된다.
CTimes time;
time.SetHour(10).SetMinute(20).SetSecond(30);
time.Print();
time.SetHour(10).SetMinute(20).SetSecond(30);
time.Print();
특별히 성능이 좋아진다거나 그런 것은 없지만, 이를 알고 있다면 코드가 간단해서 보기 쉽지 않을까 생각한다. 앞으로 잘 이용하면 좋은 문법이 될 것 같다.
'Programming > C++ Language' 카테고리의 다른 글
Unique Pointer (0) | 2014.03.03 |
---|---|
[C++] 동적바인딩( Dynamic binding ) (0) | 2011.01.03 |
[C++] 참조 변수 (1) | 2010.07.31 |
[C++] 참조 반환 (0) | 2010.07.31 |
[C++] 클래스 I (0) | 2010.07.21 |
3JUL
글
[C++] 참조 변수
Programming/C++ Language
2010. 7. 31. 17:22
참조 반환에 이어 참조 변수에 대해 알아보자.
참조 변수는 DataType& 를 이용하여 선언을 한다. 그리고, 어떤 변수의 참조를 가지도록 초기화할 때는 변수를 선언 할 때만 가능하다.
아래의 코드를 보고, 결과를 예상해 보자.
결과는 아래와 같다.( 상자 안을 마우스로 클릭하여 영역을 잡으면 보인다. )
결과 처럼, nRef = b 구문을 실행 할 떄는 nRef 가 b 변수를 참조 하는 것이 아니라, 이미 nRef 는 a 변수를 참조 하고 있으므로, b의 값을 a 에 대입을 하게 된다.
이러한 참조변수를 이용하여 Call by Reference 를 이용 할 수 있다. C에서는 Call by Reference 를 이용하기 위해서 포인터 변수를 사용했지만, C++ 에서는 대신에 참조변수를 이용하면 된다.
-> void Func( int& param1 ) {}
참조 변수는 DataType& 를 이용하여 선언을 한다. 그리고, 어떤 변수의 참조를 가지도록 초기화할 때는 변수를 선언 할 때만 가능하다.
아래의 코드를 보고, 결과를 예상해 보자.
int a = 10, b = 20;
int& nRef = a;
cout << "a is " << a << endl;
nRef = 100;
cout << "a is " << a << endl;
nRef = b;
cout << "a is " << a << endl;
cout << "b is " << b << endl;
int& nRef = a;
cout << "a is " << a << endl;
nRef = 100;
cout << "a is " << a << endl;
nRef = b;
cout << "a is " << a << endl;
cout << "b is " << b << endl;
결과는 아래와 같다.( 상자 안을 마우스로 클릭하여 영역을 잡으면 보인다. )
a is 10
a is 100
a is 20
b is 20
a is 100
a is 20
b is 20
결과 처럼, nRef = b 구문을 실행 할 떄는 nRef 가 b 변수를 참조 하는 것이 아니라, 이미 nRef 는 a 변수를 참조 하고 있으므로, b의 값을 a 에 대입을 하게 된다.
이러한 참조변수를 이용하여 Call by Reference 를 이용 할 수 있다. C에서는 Call by Reference 를 이용하기 위해서 포인터 변수를 사용했지만, C++ 에서는 대신에 참조변수를 이용하면 된다.
-> void Func( int& param1 ) {}
'Programming > C++ Language' 카테고리의 다른 글
[C++] 동적바인딩( Dynamic binding ) (0) | 2011.01.03 |
---|---|
[C++] this 포인터 사용하기 (0) | 2010.07.31 |
[C++] 참조 반환 (0) | 2010.07.31 |
[C++] 클래스 I (0) | 2010.07.21 |
[C++] C++상에서 발생하는 name mangling에 관한 내용 (0) | 2010.07.16 |
3JUL
글
[C++] 참조 반환
Programming/C++ Language
2010. 7. 31. 16:54
C++ 의 문법 중의 하나인, 참조변수가 있다. 이를 잘못 사용하게 되면 객체지향의 규칙을 깨버릴 수 있다. 그리고, 컴파일 에러는 전혀 나지 않는다. 한번 살펴 보도록 하자.
Times.h
Times.cpp
위와 같이 Times 클래스가 선언이 되어 있고, GetHour 유틸리티 함수는 int형이 아니라 int& 즉, int 참조변수형을 리턴하고 있다.
이제, 아래의 Main 문을 보도록 하자. 세번의 출력 결과를 예상해 보자.
main.cpp
출력 결과는 아래와 같다..( 상자 안을 마우스로 클릭하여 영역을 잡으면 보인다. )
즉, 참조 변수 형으로 변수를 받게 되면 참조형 변수는 private, public 여부에 관계없이 변경을 할 수 있다. 물론 Get 함수에서 포인터로 변수의 주소를 넘겨줄 경우, 받는 쪽에서 private 이든, public 이든 관계없이 이를 변경 시킬수 있다. 클래스 캡슐화를 위반하는 문법을 사용 하는 것을 피하도록 하자.
값을 받아서 사용 할 때의 문법상의 차이점 말고는 실질적인 원리는 어떻게 다른지 잘 모르겠다. 알아봐야겠다. :)
Times.h
class CTimes
{
public:
CTimes( int = 0, int = 0, int = 0 );
~CTimes();
int& GetHour();
void Print();
private:
int hour;
int minute;
int second;
};
{
public:
CTimes( int = 0, int = 0, int = 0 );
~CTimes();
int& GetHour();
void Print();
private:
int hour;
int minute;
int second;
};
Times.cpp
int& CTimes::GetHour()
{
{
return hour;
}
void CTimes::Print()
{
void CTimes::Print()
{
cout << "hour is " << hour << endl;
}
위와 같이 Times 클래스가 선언이 되어 있고, GetHour 유틸리티 함수는 int형이 아니라 int& 즉, int 참조변수형을 리턴하고 있다.
이제, 아래의 Main 문을 보도록 하자. 세번의 출력 결과를 예상해 보자.
main.cpp
int main()
{
{
Ctimes time( 1, 2 );
time.Print();
int a = time.GetHour();
a = 5;
time.Print();
int& b = time.GetHour();
b = 10;
time.Print();
return 0;
time.Print();
int a = time.GetHour();
a = 5;
time.Print();
int& b = time.GetHour();
b = 10;
time.Print();
return 0;
}
출력 결과는 아래와 같다..( 상자 안을 마우스로 클릭하여 영역을 잡으면 보인다. )
hour is 1
hour is 1
hour is 10
hour is 1
hour is 10
즉, 참조 변수 형으로 변수를 받게 되면 참조형 변수는 private, public 여부에 관계없이 변경을 할 수 있다. 물론 Get 함수에서 포인터로 변수의 주소를 넘겨줄 경우, 받는 쪽에서 private 이든, public 이든 관계없이 이를 변경 시킬수 있다. 클래스 캡슐화를 위반하는 문법을 사용 하는 것을 피하도록 하자.
값을 받아서 사용 할 때의 문법상의 차이점 말고는 실질적인 원리는 어떻게 다른지 잘 모르겠다. 알아봐야겠다. :)
'Programming > C++ Language' 카테고리의 다른 글
[C++] this 포인터 사용하기 (0) | 2010.07.31 |
---|---|
[C++] 참조 변수 (1) | 2010.07.31 |
[C++] 클래스 I (0) | 2010.07.21 |
[C++] C++상에서 발생하는 name mangling에 관한 내용 (0) | 2010.07.16 |
[C++] Errors : cannot allocate an object of abstract type '???' (0) | 2010.06.14 |
2JUL
글
[C++] 클래스 I
Programming/C++ Language
2010. 7. 21. 15:42
생성자
: 기본 생성자를 호출하지 않거나, 만들지 않더라도 묵시적으로 호출 및 생성이 되어서 호출이 된다. 물론, 생성자가 만들어지지 않았을 경우, 아무동작도 하지 않는다.
: 생성자는 오버로드 가능하여 클래스 객체를 초기화 하는 다양한 방법을 제공한다.
: 디폴트 생성자 - 클래스당 하나의 디폴트 생성자가 존재 할 수 있다. 라고 책에 되어 있다. 사실상 컴파일 상에서는 디폴트 생성자가 여러개 존재 할 수 있다.
그리고, CTimes time( 1, 2, 3 ); 을 호출하게 되면, ① 의 생성자가 호출 된다.
하지만, CTimes time( 1, 2 ); 을 호출하게 되면, "ambiguous call to overloaded function" 이라는 에러 문구를 보여준다. 애매한 호출을 한다는 것이다. time( 1, 2 ) 를 호출하면, ① 도 가능하고, ② 도 가능하다. 그러므로 컴파일러에서 혼돈을 하게 되는 것이다.
소멸자
: 생성자와 마찬가지로 명시적으로 만들지 않더라도, C++ 컴파일러에서 아무것도 하지 않는 디폴트 소멸자를 만들어준다.
: 소멸자는 오버로드가 불가능하다.
생성자, 소멸자 호출 순서
: 일반적으로 소멸자는 생성자가 호출되는 순서의 반대이다.
: 전역적으로 정의된 객체의 생성자는 main 함수를 비롯한 파일 내의 함수가 실행을 시작하기 전에 호출 된다. 그리고, 전역 객체의 생성자가 호출되는 순서는 보장되지 않는다.
: 전역 및 static 객체의 소멸자는 main 함수가 종료되거나, exit 함수가 호출될 때 호출된다.
: abort 함수를 호출하여 종료하게 되면, 전역 및 static 객체의 소멸자는 호출되지 않는다.
: static 지역 객체의 생성자는, main에서 해당 코드 부분이 수행될 때 호출이 되고,
Inline 함수
SetField 같은 경우에는 클래스 외부에서 정의된 멤버 함수 이므로 inline 키워드를 명시적으로 붙여 줘야 inline으로 호출을 하도록 요청 할 수 있다.
참고로, inline 으로 명시한다고 해서 항상 inline 으로 호출된다는 보장을 하지 않는다.
private 데이터 멤버에 참조반환
Class A
{
public:
int &Time::badSetHour( int h )
{
.....
위와 같이, private 변수를 참조반환을 하는 경우, hour 의 값을 반환하는 것이 아니라 hour 변수 자체 반환하는 것 처럼 되기 때문에, 외부에서 참조반환을 사용하여 private 변수를 직접 접근가능하게 되서, 객체지향에 위배되게 된다. 따라서 참조반환은 사용하지 않도록 하자.
위의 경우, a에서 10을 넣게 되면, time 객체의 private 변수인 hour 에 10이 들어가게 된다.
: 기본 생성자를 호출하지 않거나, 만들지 않더라도 묵시적으로 호출 및 생성이 되어서 호출이 된다. 물론, 생성자가 만들어지지 않았을 경우, 아무동작도 하지 않는다.
: 생성자는 오버로드 가능하여 클래스 객체를 초기화 하는 다양한 방법을 제공한다.
: 디폴트 생성자 - 클래스당 하나의 디폴트 생성자가 존재 할 수 있다. 라고 책에 되어 있다. 사실상 컴파일 상에서는 디폴트 생성자가 여러개 존재 할 수 있다.
class CTimes
{
public:
{
public:
~CTimes(void);
CTimes( int = 0, int = 0, int = 0 ); - ①
CTimes( int = 0, int = 0 ); - ②
CTimes( int = 0, int = 0, int = 0 ); - ①
CTimes( int = 0, int = 0 ); - ②
....
}
}
그리고, CTimes time( 1, 2, 3 ); 을 호출하게 되면, ① 의 생성자가 호출 된다.
하지만, CTimes time( 1, 2 ); 을 호출하게 되면, "ambiguous call to overloaded function" 이라는 에러 문구를 보여준다. 애매한 호출을 한다는 것이다. time( 1, 2 ) 를 호출하면, ① 도 가능하고, ② 도 가능하다. 그러므로 컴파일러에서 혼돈을 하게 되는 것이다.
소멸자
: 생성자와 마찬가지로 명시적으로 만들지 않더라도, C++ 컴파일러에서 아무것도 하지 않는 디폴트 소멸자를 만들어준다.
: 소멸자는 오버로드가 불가능하다.
생성자, 소멸자 호출 순서
: 일반적으로 소멸자는 생성자가 호출되는 순서의 반대이다.
: 전역적으로 정의된 객체의 생성자는 main 함수를 비롯한 파일 내의 함수가 실행을 시작하기 전에 호출 된다. 그리고, 전역 객체의 생성자가 호출되는 순서는 보장되지 않는다.
: 전역 및 static 객체의 소멸자는 main 함수가 종료되거나, exit 함수가 호출될 때 호출된다.
: abort 함수를 호출하여 종료하게 되면, 전역 및 static 객체의 소멸자는 호출되지 않는다.
: static 지역 객체의 생성자는, main에서 해당 코드 부분이 수행될 때 호출이 되고,
Inline 함수
Class A
{
위와 같이, 빨간색의 멤버함수가 클래스 몸체에 정의 되어 있으면, C++ 컴파일러는 그 멤버 함수를 인라인으로 호출하려 할 것이다.{
result GetResult() { return __r; }
result SetValue( int nVal ) { __val = nVal };
result SetField( String str );
result SetValue( int nVal ) { __val = nVal };
result SetField( String str );
}
inline result A::SetField( String str )
{
inline result A::SetField( String str )
{
__str = str;
}
SetField 같은 경우에는 클래스 외부에서 정의된 멤버 함수 이므로 inline 키워드를 명시적으로 붙여 줘야 inline으로 호출을 하도록 요청 할 수 있다.
참고로, inline 으로 명시한다고 해서 항상 inline 으로 호출된다는 보장을 하지 않는다.
private 데이터 멤버에 참조반환
Class A
{
public:
int &badSetHour(int );
private:
int hour;
}
int &Time::badSetHour( int h )
{
.....
return hour;
}
main()
{
int& a = time.GetHour();
a = 10;
}
main()
{
int& a = time.GetHour();
a = 10;
}
위와 같이, private 변수를 참조반환을 하는 경우, hour 의 값을 반환하는 것이 아니라 hour 변수 자체 반환하는 것 처럼 되기 때문에, 외부에서 참조반환을 사용하여 private 변수를 직접 접근가능하게 되서, 객체지향에 위배되게 된다. 따라서 참조반환은 사용하지 않도록 하자.
위의 경우, a에서 10을 넣게 되면, time 객체의 private 변수인 hour 에 10이 들어가게 된다.
'Programming > C++ Language' 카테고리의 다른 글
[C++] 참조 변수 (1) | 2010.07.31 |
---|---|
[C++] 참조 반환 (0) | 2010.07.31 |
[C++] C++상에서 발생하는 name mangling에 관한 내용 (0) | 2010.07.16 |
[C++] Errors : cannot allocate an object of abstract type '???' (0) | 2010.06.14 |
[C++] 복사 생성자 (0) | 2010.05.31 |
1JUL
글
[C++] C++상에서 발생하는 name mangling에 관한 내용
Programming/C++ Language
2010. 7. 16. 08:56
C++상에서 발생하는 name mangling에 관한 내용
1. name mangling 이란?
간단히 말하면 compiler 가 임의로 함수나 변수의 이름을 변경하는 것을 의미합니다.
그렇다면 왜 함수나 변수의 이름을 변경하는 것인가?
이를 설명하기 위해서는 C++언어의 성격상 function overloading을 먼저 설명해야 하는데요.
function overloading이란 개발자가 소스코드를 작성할때 같은 이름으로 다른 기능들을 수행하는 함수를 만들수 있도록 하는 기능을 예기합니다..
예를 들면,
int Add( int a,int b){return a+b;}
float Add( float a,float b){return a+b;}
float Add( float a,float b, float c){return a+b+c;}
위와 같이 Add라는 함수를 int형을 더하는 함수, float 형을 더하는 함수, 세 변수를 더하는 함수등등 여러개의 함수를 작성하고, 개발자가 이를 임의로 아무거나 불러 쓸 수 있습니다.
이런것이 가능하도록 해주는 기능이 바로 함수 overloading이라는 개념입니다..
그럼 compiler는 소스 코드에서 Add를 호출 했을때 어떻게 각각의 Add를 알아서 찾는가 하는 의문이 생길수 있을것인데, 이를 가능하게 해주는것이 name mangling 이다.
compiler는 symbol을 생성할때 함수 이름과 함수 parameter를 고려 하여 symbol을 만듭니다..
즉,
int Add( int a,int b) -> Add + int+ int --> Addii 와 같은 형식으로 만든다는 것입니다..
물론, compiler 마다 다른 mangling 규칙을 가지고 있습니다..
인터넷에 떠도는 문서들을 찾다보니 아주 한눈에 잘 들어오도록 정리된 표가 있어서 샤샥!! 퍼옴...
이유는 C에서는 function overloading을 지원하지 않기 때문에 한 binary안에서는 하나의 function만 존재 합니다.
하지만 !!! 실제로 compile을 해보면 각 함수 이름을 살짝 바꿔 놓기는 합니다. 예를 들면,
void Add(int a,int b) ---> _Add 라는 형식 으로 앞에 '_'를 붙이는 경우부터 해서... 이것 역시 compiler가 각자 규칙을 가지고 진행 합니다.
이런 mangled name 을 확인 해보는 방법은 compile 된 object file(xxx.o) 나 실행 화일 또는 .lib 파일을 hex editor로 열어서 확인 해보면 눈으로 볼 수 있답니다.
2. extern "C" ?
자 , 사실 name mangling 이 발생한다는 것이 개발자가 알고 있어야 하는 지식이기는 하나 그렇다고 mangled 된 이름 가지고 뭘 어떻게 하라는 예기가 사실 그다지 중요하지 않다.
이글의 본 취지는 사실 extern "C" 에 있다.
저도 개발 초기에는 막연하게 "extern "C"를 붙이면 함수의 이름이 C 처럼 나오기 때문에 C++로 짜여진 함수도 C에서 사용할 수 있다." 라고만 알고 있었습니다.
이런 저런 개발을 하다보니 정확한 용법이나 메카니즘을 이해하지 않고 막연하게 사용하는 코드들이나 개념들은 결국 부매랑이 되어 저에게 돌아오더군요.!!
무슨 말이냐 하면,C++에서 짠 함수가 C에서도 사용할수 있게 하려면 extern "C" 를 붙이라는데 어디다? 어떻게 ? 라는 의문이 생겨날 것입니다.
근데 extern "C"에 대해 잘 모르는 사람이 위와 같은 조언을 들었으면,, 분명 extern "C"를 남발하게 됩니다.!! 이는 결국 나중에 compile error를 양산하기도 하고, 코드를 지저분하게 만들기도 하고, 아무튼 문제를 많이 일으키게 되죠.!!! 그런적 없다구요? 전 당했습니다.!!
자 그럼 하나 하나 차근 차근 짚어 보겠습니다.
extern "C" --> 이 형식은 extern "C" 이후에 오는 내용을 name mangling 하지 않고 C처럼 symbol을 만들 어라 라는 명령어입니다.
즉, abc.cpp 라는 소스코드에서 아래 abc라는 함수와 def라는 함수를 예로 들어보면,
def는 ii 같은 것이 추가되지 않고 그냥 def라는 이름을 갖게 됩니다.
그러면, 모든 함수 구현 루틴에 extern "C" 를 붙이는것이 사실 귀찮고 힘든 일입니다.
그래서 , 연륜이 있는 개발자들은(저처럼 ㅋㅋㅋ) extern "C" {}를 활용하게 되는 것이죠.
이렇게 extern "C" {}를 사용하면 {} 안에 있는 모든 내용은 name을 mangling하지 않는 다는 선언이 됩니다.
이렇게 사용하면 모든 함수들을 따라다니면서 extern "C" 를 붙일 필요가 없어지는 것입니다.
또, 다른 형식으로 사용하는 case가 Header file extern "C"를 사용하는 경우가 있습니다.
(대단히 많이 사용하는 형식입니다. 이유는 관리하기가 편해서? )
자!! 이제 위와 같은 포멧으로 주로 많이들 사용하는데, 위의 내용을 보면 어떤가요? 문제가 있어보이나요 없어보이나요?
얼핏 보기엔 아무런 문제가 없어 보입니다.
하지만!!!!!
한가지 찾아낸 분이 있군요.... 그렇숩니다. ^^a 위의 해더파일은 C 파일에서는 include 해서 사용할 수 없습니다.
이유는 extern "C" 는 C++ compiler에서만 지원하기 때문입니다.
a.c 에서 #include "abc.h"를 사용하면 error가 발생합니다.
그래서 #ifdef __cplusplus 를 이용해서 extern "C" 를 묶어서 사용합니다.
이렇게 사용함으로 해서 C compiler에서는 extern "C"를 사용하지 않고 compile됩니다.
C compiler에서는 c니까 당연히 name mangling이 발생하지 않겠죠.!!!! <-- 요거 중요한 예기...
자 그럼 두번째 문제점은 어디에 있을까요??
못찾겠죠... 흔히들 실수 할 수 있는 부분입니다. ( 찾았다구요?? 이 글 왜 읽고 있습니까?? 자리로 돌아가서 일하세요.. ㅎㅎ 다 아시는 분이.. ~~)
두번째 문제는 사실 편하게 쓰고자 extern "C" {} 를 사용하는데 이게 아래와 같이 사용하면 문제를 만듭니다. 무슨 말이냐 하면.. extern "C" {} 중간에 header file을 포함하고 있죠??
1. name mangling 이란?
간단히 말하면 compiler 가 임의로 함수나 변수의 이름을 변경하는 것을 의미합니다.
그렇다면 왜 함수나 변수의 이름을 변경하는 것인가?
이를 설명하기 위해서는 C++언어의 성격상 function overloading을 먼저 설명해야 하는데요.
function overloading이란 개발자가 소스코드를 작성할때 같은 이름으로 다른 기능들을 수행하는 함수를 만들수 있도록 하는 기능을 예기합니다..
예를 들면,
int Add( int a,int b){return a+b;}
float Add( float a,float b){return a+b;}
float Add( float a,float b, float c){return a+b+c;}
위와 같이 Add라는 함수를 int형을 더하는 함수, float 형을 더하는 함수, 세 변수를 더하는 함수등등 여러개의 함수를 작성하고, 개발자가 이를 임의로 아무거나 불러 쓸 수 있습니다.
이런것이 가능하도록 해주는 기능이 바로 함수 overloading이라는 개념입니다..
그럼 compiler는 소스 코드에서 Add를 호출 했을때 어떻게 각각의 Add를 알아서 찾는가 하는 의문이 생길수 있을것인데, 이를 가능하게 해주는것이 name mangling 이다.
compiler는 symbol을 생성할때 함수 이름과 함수 parameter를 고려 하여 symbol을 만듭니다..
즉,
int Add( int a,int b) -> Add + int+ int --> Addii 와 같은 형식으로 만든다는 것입니다..
물론, compiler 마다 다른 mangling 규칙을 가지고 있습니다..
인터넷에 떠도는 문서들을 찾다보니 아주 한눈에 잘 들어오도록 정리된 표가 있어서 샤샥!! 퍼옴...
Compiler | void h(int) | void h(int, char) | void h(void) |
---|---|---|---|
Intel C++ 8.0 for Linux | _Z1hi | _Z1hic | _Z1hv |
HP aC++ A.05.55 IA-64 | _Z1hi | _Z1hic | _Z1hv |
GNU GCC 3.x and 4.x | _Z1hi | _Z1hic | _Z1hv |
HP aC++ A.03.45 PA-RISC | h__Fi | h__Fic | h__Fv |
GNU GCC 2.9x | h__Fi | h__Fic | h__Fv |
Microsoft VC++ v6/v7 | ?h@@YAXH@Z | ?h@@YAXHD@Z | ?h@@YAXXZ |
Digital Mars C++ | ?h@@YAXH@Z | ?h@@YAXHD@Z | ?h@@YAXXZ |
Borland C++ v3.1 | @h$qi | @h$qizc | @h$qv |
OpenVMS C++ V6.5 (ARM mode) | H__XI | H__XIC | H__XV |
OpenVMS C++ V6.5 (ANSI mode) | CXX$__7H__FI0ARG51T | CXX$__7H__FIC26CDH77 | CXX$__7H__FV2CB06E8 |
OpenVMS C++ X7.1 IA-64 | CXX$_Z1HI2DSQ26A | CXX$_Z1HIC2NP3LI4 | CXX$_Z1HV0BCA19V |
SunPro CC | __1cBh6Fi_v_ | __1cBh6Fic_v_ | __1cBh6F_v_ |
Tru64 C++ V6.5 (ARM mode) | h__Xi | h__Xic | h__Xv |
Tru64 C++ V6.5 (ANSI mode) | __7h__Fi | __7h__Fic | __7h__Fv |
Watcom C++ 10.6 | W?h$n(i)v | W?h$n(ia)v | W?h$n()v |
위와 같이 컴파일러 마다 다른 mangling 규칙을 가지고 있답니다..
이유는 C에서는 function overloading을 지원하지 않기 때문에 한 binary안에서는 하나의 function만 존재 합니다.
하지만 !!! 실제로 compile을 해보면 각 함수 이름을 살짝 바꿔 놓기는 합니다. 예를 들면,
void Add(int a,int b) ---> _Add 라는 형식 으로 앞에 '_'를 붙이는 경우부터 해서... 이것 역시 compiler가 각자 규칙을 가지고 진행 합니다.
이런 mangled name 을 확인 해보는 방법은 compile 된 object file(xxx.o) 나 실행 화일 또는 .lib 파일을 hex editor로 열어서 확인 해보면 눈으로 볼 수 있답니다.
2. extern "C" ?
자 , 사실 name mangling 이 발생한다는 것이 개발자가 알고 있어야 하는 지식이기는 하나 그렇다고 mangled 된 이름 가지고 뭘 어떻게 하라는 예기가 사실 그다지 중요하지 않다.
이글의 본 취지는 사실 extern "C" 에 있다.
저도 개발 초기에는 막연하게 "extern "C"를 붙이면 함수의 이름이 C 처럼 나오기 때문에 C++로 짜여진 함수도 C에서 사용할 수 있다." 라고만 알고 있었습니다.
이런 저런 개발을 하다보니 정확한 용법이나 메카니즘을 이해하지 않고 막연하게 사용하는 코드들이나 개념들은 결국 부매랑이 되어 저에게 돌아오더군요.!!
무슨 말이냐 하면,C++에서 짠 함수가 C에서도 사용할수 있게 하려면 extern "C" 를 붙이라는데 어디다? 어떻게 ? 라는 의문이 생겨날 것입니다.
근데 extern "C"에 대해 잘 모르는 사람이 위와 같은 조언을 들었으면,, 분명 extern "C"를 남발하게 됩니다.!! 이는 결국 나중에 compile error를 양산하기도 하고, 코드를 지저분하게 만들기도 하고, 아무튼 문제를 많이 일으키게 되죠.!!! 그런적 없다구요? 전 당했습니다.!!
자 그럼 하나 하나 차근 차근 짚어 보겠습니다.
extern "C" --> 이 형식은 extern "C" 이후에 오는 내용을 name mangling 하지 않고 C처럼 symbol을 만들 어라 라는 명령어입니다.
즉, abc.cpp 라는 소스코드에서 아래 abc라는 함수와 def라는 함수를 예로 들어보면,
1 |
int abc( int a, int b) //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
2 |
{ |
3 |
return 0; |
4 |
} |
5 |
|
6 |
extern "C" int def( int a, int b) // def 라는 symbol을 가지게 되는 것입니다. |
7 |
{ |
8 |
return 0; |
9 |
} |
그러면, 모든 함수 구현 루틴에 extern "C" 를 붙이는것이 사실 귀찮고 힘든 일입니다.
그래서 , 연륜이 있는 개발자들은(저처럼 ㅋㅋㅋ) extern "C" {}를 활용하게 되는 것이죠.
01 |
<FILE: abc.cpp= "" > |
02 |
|
03 |
extern "C" |
04 |
{ //<-- extern 시작 |
05 |
int abc( int a, int b) //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
06 |
{ |
07 |
return 0; |
08 |
} |
09 |
|
10 |
int def( int a, int b) // def 라는 symbol을 가지게 되는 것입니다. |
11 |
{ |
12 |
return 0; |
13 |
} |
14 |
} //extern 끝 |
15 |
</FILE:> |
이렇게 사용하면 모든 함수들을 따라다니면서 extern "C" 를 붙일 필요가 없어지는 것입니다.
또, 다른 형식으로 사용하는 case가 Header file extern "C"를 사용하는 경우가 있습니다.
(대단히 많이 사용하는 형식입니다. 이유는 관리하기가 편해서? )
01 |
<FILE: abc.h= "" > |
02 |
#ifndef __ABC_H__ |
03 |
#define __ABC_H__ |
04 |
|
05 |
extern "C" |
06 |
{ //<-- extern 시작 |
07 |
|
08 |
#include "sysconfig.h" |
09 |
#include "hello.h" |
10 |
#include "test.h" |
11 |
|
12 |
//function prototype |
13 |
int abc( int a, int b); //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
14 |
int def( int a, int b); // def 라는 symbol을 가지게 되는 것입니다. |
15 |
|
16 |
|
17 |
} //extern 끝 |
18 |
|
19 |
#endif //__ABC_H__ |
20 |
</FILE:> |
얼핏 보기엔 아무런 문제가 없어 보입니다.
하지만!!!!!
한가지 찾아낸 분이 있군요.... 그렇숩니다. ^^a 위의 해더파일은 C 파일에서는 include 해서 사용할 수 없습니다.
이유는 extern "C" 는 C++ compiler에서만 지원하기 때문입니다.
a.c 에서 #include "abc.h"를 사용하면 error가 발생합니다.
그래서 #ifdef __cplusplus 를 이용해서 extern "C" 를 묶어서 사용합니다.
01 |
<FILE: abc.h= "" > |
02 |
#ifndef __ABC_H__ |
03 |
#define __ABC_H__ |
04 |
|
05 |
#ifdef __cplusplus |
06 |
extern "C" { //<-- extern 시작 |
07 |
#endif |
08 |
#include "sysconfig.h" |
09 |
#include "hello.h" |
10 |
#include "test.h" |
11 |
|
12 |
//function prototype |
13 |
int abc( int a, int b); //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
14 |
int def( int a, int b); // def 라는 symbol을 가지게 되는 것입니다. |
15 |
|
16 |
#ifdef __cplusplus |
17 |
} //extern 끝 |
18 |
#endif |
19 |
#endif //__ABC_H__ |
20 |
</FILE:> |
C compiler에서는 c니까 당연히 name mangling이 발생하지 않겠죠.!!!! <-- 요거 중요한 예기...
자 그럼 두번째 문제점은 어디에 있을까요??
못찾겠죠... 흔히들 실수 할 수 있는 부분입니다. ( 찾았다구요?? 이 글 왜 읽고 있습니까?? 자리로 돌아가서 일하세요.. ㅎㅎ 다 아시는 분이.. ~~)
두번째 문제는 사실 편하게 쓰고자 extern "C" {} 를 사용하는데 이게 아래와 같이 사용하면 문제를 만듭니다. 무슨 말이냐 하면.. extern "C" {} 중간에 header file을 포함하고 있죠??
그래서 abc.h 가 sysconfig.h를 include 하고 있고, sysconfig.h는 def.h를 include하고 있다면,
extern "C"{ //<-- abc.h
extern "C" { //<--sysconfig.h
extern "C"{//<-- sysconfig.h 내에서 include 하고 있는 def.h
extern "C" { //<--sysconfig.h
extern "C"{//<-- sysconfig.h 내에서 include 하고 있는 def.h
이런 형식으로 가다가 결국 extern "C"가 너무 많이 중복 사용되었다는 에러메세지를 받고 당황하게 되실 것입니다. ㅎ
결국 VC에서는 아래와 같은 에러를 내면서 컴파일 에러를 냅니다.
fatal error C1045: compiler limit : linkage specifications nested too deeply
visual Studio 에서는 depth 제한이 10으로 되어있습니다.
그래서 당황하여 여기저기 extern "C"를 찾아서 지우고 옮기고 하다보면, 나중에 name mangling 되어 link error를 메세지를 받고 뒷목을 붙잡고 쓰러질 수도 있습니다.
이래서 어설프게 알고 사용하면 절대 안된다는 예깁니다.
저는 그래서 아래와 같이 header file 선언부 아래에 extern "C"를 사용하기를 권합니다.
모든 header file들이 위와 같이 include file 아래서 부터 extern "C"를 사용하면, 아래와 같이 중복되지 않게 되어 depth가 늘어나지 않습니다. <-- 요거 꽤 중요한 팁이니 자기가 맡고 있는 프로젝트가 있다면 한번 살펴보세요!! ㅎ
extern "C"
{//<-- sysconfig.h 내에서 include 하고 있는 def.h
}
extern "C"
{ //<--sysconfig.h
}
extern "C"
{ //<-- abc.h
:
:
}
자!! 이제 가장 중요하고 핵심이 되는 문제가 남았습니다.
이 문제는 위에 있는 해더파일 내용으로만 봐서는 절대로 찾을 수 없는 내용인데요..
뭐냐하면..
위와 같이 header 파일을 잘 만들었다 하더라도 link error를 당할 수 있는 경우가 있다는 것입니다.!!
어떤 경우일까요? 흠흠.ㅋ ㅋㅋ
어떤 경우냐 하면 , 우리가 만든 abc 와 def 함수의 몸체는 abc.cpp 에 있죠?
function name 이 mangling 될때가 언제라고 했죠?
link 할때? 아니죠~~ compile 할때.. 즉 compiler가 abc.o를 만들때 name이 mangling됩니다.
즉, name mangling을 막을려면 abc.cpp가 compile될때 막아야 합니다.
즉 그말은 abc.cpp가 compile될때 이미 extern "C"가 함수들에 선언 되어 있어야 name mangling을 막을 수 있다는 예기 입니다.
이미 abc.h에 extern "C"로 잘 감싸 놨는데 무슨 예기냐 ~~ 모르겠다... 하시는 분들 계실 겁니다.
abc.cpp가 아래와 같이 extern "C"가 없다고 합시다. 그리고 main.c에서 아래와 같이 abc를 사용했다고 합시다.
아.. 하시는 분 있을거 같은데 ㅎㅎㅎ. 좀 감이 오시나요? 어쨌든 설명을 이어 가겠습니다.
main 에서 abc를 호출하면 main은 c 파일이기 때문에 mangliing 안된 abc 를 symbol로 link 합니다.
하지만 abc.cpp를 compiler가 컴파일 할때는 abcii, defii 로 mangling 된 이름으로 symbol을 만듭니다.
왜? abc.cpp를 보십시오. abc.cpp안에는 어디에도 extern "C"라고 선언된 부분이 없습니다.
그래서 C++ compiler는 함수 이름을 mangling해버립니다.
그래서 main에서 부른 abc는 symbol만있고 body가 없기 때문에 link 시에 에러가 발생합니다.
이제 아셨죠.?? 이런 정확한 메카니즘을 모르면 왜 링크에러나는지 모르고 이것 저것 삽질하다 수정되면 그냥 넘어가 버리게 됩니다.!!! 코드만 지저분해지게 만들구요..
그러면 abc, def가 mangling 안되게 만들려면 어떻게 할까요? 맨 위에 예제 처럼 cpp 파일 처음부터 끝까지 extern "C"로 감싸면 되겠죠?
제가 적극 추천하는 방법은 abc.h를 abc.c 에서 include 하는 방법을 추천합니다.
이렇게 하면 compiler가 abc.cpp 를 컴파일 할때 abc.h에 있는 extern "C"{} 로 되어있는 영역 내부의 내용에 해당하는 abc,def함수들을 모두 mangling안되게 해준답니다.
3.마치며!!
항상 강조하지만 100% 이해하지 못하는 code나 함수를 내 프로그램에 추가하게 되면 반드시 그 대가를 치르게 됩니다.!!! 이는 불변의 진리입니다.!!!
그러니 여러분들도 "남들이 이렇게 쓰니 나도 이렇게 써야지 " 이렇게 하지 마시고, 자신이 사용하고자 하는 것에 대한 내용을 최대한 깊게 이해하려고 노력하십시오.
그러면 나중에 돌아올 부매랑을 막을 방법도 갖게 될 것입니다.!!
출처 : http://spikez.tistory.com/19
저는 그래서 아래와 같이 header file 선언부 아래에 extern "C"를 사용하기를 권합니다.
01 |
<FILE: abc.h= "" > |
02 |
#ifndef __ABC_H__ |
03 |
#define __ABC_H__ |
04 |
|
05 |
//<<REMOVED>> |
06 |
#include "sysconfig.h" |
07 |
#include "hello.h" |
08 |
#include "test.h" |
09 |
|
10 |
#ifdef __cplusplus |
11 |
extern "C" { //<-- extern 시작 |
12 |
#endif |
13 |
//function prototype |
14 |
int abc( int a, int b); //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
15 |
int def( int a, int b); // def 라는 symbol을 가지게 되는 것입니다. |
16 |
|
17 |
#ifdef __cplusplus |
18 |
} //extern 끝 |
19 |
#endif |
20 |
#endif //__ABC_H__ |
21 |
</REMOVED></FILE:> |
extern "C"
{//<-- sysconfig.h 내에서 include 하고 있는 def.h
}
extern "C"
{ //<--sysconfig.h
}
extern "C"
{ //<-- abc.h
:
:
}
자!! 이제 가장 중요하고 핵심이 되는 문제가 남았습니다.
이 문제는 위에 있는 해더파일 내용으로만 봐서는 절대로 찾을 수 없는 내용인데요..
뭐냐하면..
위와 같이 header 파일을 잘 만들었다 하더라도 link error를 당할 수 있는 경우가 있다는 것입니다.!!
어떤 경우일까요? 흠흠.ㅋ ㅋㅋ
어떤 경우냐 하면 , 우리가 만든 abc 와 def 함수의 몸체는 abc.cpp 에 있죠?
function name 이 mangling 될때가 언제라고 했죠?
link 할때? 아니죠~~ compile 할때.. 즉 compiler가 abc.o를 만들때 name이 mangling됩니다.
즉, name mangling을 막을려면 abc.cpp가 compile될때 막아야 합니다.
즉 그말은 abc.cpp가 compile될때 이미 extern "C"가 함수들에 선언 되어 있어야 name mangling을 막을 수 있다는 예기 입니다.
이미 abc.h에 extern "C"로 잘 감싸 놨는데 무슨 예기냐 ~~ 모르겠다... 하시는 분들 계실 겁니다.
abc.cpp가 아래와 같이 extern "C"가 없다고 합시다. 그리고 main.c에서 아래와 같이 abc를 사용했다고 합시다.
01 |
<FILE: abc.cpp= "" > |
02 |
|
03 |
|
04 |
int abc( int a, int b) //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
05 |
{ |
06 |
return 0; |
07 |
} |
08 |
|
09 |
int def( int a, int b) // def 라는 symbol을 가지게 되는 것입니다. |
10 |
{ |
11 |
return 0; |
12 |
} |
13 |
|
14 |
</FILE:> |
01 |
<FILE: main.c= "" > |
02 |
|
03 |
#include "abc.h" |
04 |
|
05 |
void main() |
06 |
{ |
07 |
abc(10,20); |
08 |
} |
09 |
|
10 |
</FILE:> |
main 에서 abc를 호출하면 main은 c 파일이기 때문에 mangliing 안된 abc 를 symbol로 link 합니다.
하지만 abc.cpp를 compiler가 컴파일 할때는 abcii, defii 로 mangling 된 이름으로 symbol을 만듭니다.
왜? abc.cpp를 보십시오. abc.cpp안에는 어디에도 extern "C"라고 선언된 부분이 없습니다.
그래서 C++ compiler는 함수 이름을 mangling해버립니다.
그래서 main에서 부른 abc는 symbol만있고 body가 없기 때문에 link 시에 에러가 발생합니다.
이제 아셨죠.?? 이런 정확한 메카니즘을 모르면 왜 링크에러나는지 모르고 이것 저것 삽질하다 수정되면 그냥 넘어가 버리게 됩니다.!!! 코드만 지저분해지게 만들구요..
그러면 abc, def가 mangling 안되게 만들려면 어떻게 할까요? 맨 위에 예제 처럼 cpp 파일 처음부터 끝까지 extern "C"로 감싸면 되겠죠?
제가 적극 추천하는 방법은 abc.h를 abc.c 에서 include 하는 방법을 추천합니다.
01 |
<FILE: abc.cpp= "" > |
02 |
|
03 |
#include "abc.h" |
04 |
|
05 |
|
06 |
int abc( int a, int b) //abcii 라는 mangled 된 이름을 symbol로 가지게 됩니다. |
07 |
{ |
08 |
return 0; |
09 |
} |
10 |
|
11 |
int def( int a, int b) // def 라는 symbol을 가지게 되는 것입니다. |
12 |
{ |
13 |
return 0; |
14 |
} |
15 |
|
16 |
</FILE:> |
3.마치며!!
항상 강조하지만 100% 이해하지 못하는 code나 함수를 내 프로그램에 추가하게 되면 반드시 그 대가를 치르게 됩니다.!!! 이는 불변의 진리입니다.!!!
그러니 여러분들도 "남들이 이렇게 쓰니 나도 이렇게 써야지 " 이렇게 하지 마시고, 자신이 사용하고자 하는 것에 대한 내용을 최대한 깊게 이해하려고 노력하십시오.
그러면 나중에 돌아올 부매랑을 막을 방법도 갖게 될 것입니다.!!
출처 : http://spikez.tistory.com/19
'Programming > C++ Language' 카테고리의 다른 글
[C++] 참조 반환 (0) | 2010.07.31 |
---|---|
[C++] 클래스 I (0) | 2010.07.21 |
[C++] Errors : cannot allocate an object of abstract type '???' (0) | 2010.06.14 |
[C++] 복사 생성자 (0) | 2010.05.31 |
[C++] Construct method (0) | 2010.05.27 |
7JUL
글
[makefile]commands commence before first target 에러
Programming
2010. 7. 7. 10:10
*** commands commence before first target. Stop 와 같은 에러가 발생하는 경우
\ 문자 뒤에 공백이 들어가서 그렇다.
Ex ) MOD := \
\ 문자 뒤에 공백이 들어가서 그렇다.
Ex ) MOD := \
$(DIR)/Test.o \
$(DIR)/Lib.o \
$(DIR)/smc.o
$(DIR)/Lib.o \
$(DIR)/smc.o
위의 예와 같이 붉은 색의 빈칸이 들어가 있으면, 에러가 발생한다.
'Programming' 카테고리의 다른 글
ARM C Compiler (0) | 2010.09.18 |
---|---|
세마포어( Semaphore ) (1) | 2010.05.31 |
Event-driven programming (0) | 2010.05.31 |
undefined reference (0) | 2010.03.26 |
XML 이란? (0) | 2010.03.26 |
1JUN
글
[C++] Errors : cannot allocate an object of abstract type '???'
Programming/C++ Language
2010. 6. 14. 19:58
이 에러의 경우, 해당 class 를 생성( new ) 하는 부분에서 뜬다.
해당 클래스의 부모 클래스를 보면, 순수가상함수가 있을 텐데, 이를 구현하지 않았을 경우
이러한 메세지를 띄워준다. 순수가상함수는 객체 전체의 메모리의 일부분을 차지하게 되고, 이를
컴파일러에서는 생각하고 있을 텐데, 이를 자식이 구현을 하지 않았을 경우에는, 해당 부분이 없으
므로, 메모리를 할당해야되는 부분을 구현하지 않았으므로, 추상타입의 객체를 할당 할 수 없다고 나
오는 것이다.
해당 클래스의 부모 클래스를 보면, 순수가상함수가 있을 텐데, 이를 구현하지 않았을 경우
이러한 메세지를 띄워준다. 순수가상함수는 객체 전체의 메모리의 일부분을 차지하게 되고, 이를
컴파일러에서는 생각하고 있을 텐데, 이를 자식이 구현을 하지 않았을 경우에는, 해당 부분이 없으
므로, 메모리를 할당해야되는 부분을 구현하지 않았으므로, 추상타입의 객체를 할당 할 수 없다고 나
오는 것이다.
'Programming > C++ Language' 카테고리의 다른 글
[C++] 클래스 I (0) | 2010.07.21 |
---|---|
[C++] C++상에서 발생하는 name mangling에 관한 내용 (0) | 2010.07.16 |
[C++] 복사 생성자 (0) | 2010.05.31 |
[C++] Construct method (0) | 2010.05.27 |
[C++] static_cast (0) | 2010.03.22 |