일반적인 함수 선언은 다음과 같다.



이와 달리 return type을 auto로 적고 인자 뒤에 -> 를 적고 적을 수 있다.



오픈 소스를 보다 보면 이런 코드들이 나온다.

'프로그래밍 > C++' 카테고리의 다른 글

선언부와 구현부를 분리할 때 주의해야 할 것 정리  (0) 2017.11.08
C와 C++의 cast  (0) 2017.10.08
함수를 못 쓰게 하기  (0) 2017.10.08
인라인 함수  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08

때때로 암시적 형변환을 프로그래머가 금지해야 하는 경우가 있다.


이를 테면 int형 인자를 받는 함수에 double형 인자를 넣게 되면 암시적 형변환이 되는데, 이를 막기위해선 두 가지 방법이 있다.


1. double 형 함수를 선언만 하고 구현하지 않는다.



이 경우 컴파일 시 foo(double)로의 참조가 정의되어 있지 않다고 링크 에러가 발생하게 된다.


2. C++ 11의 delete function 기능을 쓴다.



이 경우 위와 달리 컴파일 시점에 에러가 발생한다.


라이브러리를 제작해서 배포하려 하면 2번 방법시에만 에러가 나니 약간 다르다.

'프로그래밍 > C++' 카테고리의 다른 글

C와 C++의 cast  (0) 2017.10.08
후위 반환 형식 trailing return type/ suffix return type  (0) 2017.10.08
인라인 함수  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08
디폴트 파라미터  (0) 2017.10.08

함수는 인자 값을 복사하고, 함수로 이동한 다음, 실행을 마치고 다시 돌아오는 반면,

인라인 함수는 컴파일 시점에 기계어 코드를 치환하기 때문에 성능 하락이 없다.


다만 인라인 함수를 사용하면 코드가 길어질 수 있기 때문에, 보통 짧은 함수들에 사용한다.


다른 파일에 있는 인라인 함수를 사용할 때는 헤더 파일 내에 구현부가 꼭 있어야 한다.

(같은 파일 내에는 상관 없다.)


위에서 인라인 함수는 "컴파일 시점"에 기계어 코드를 치환한다고 했는데, 헤더에 선언하고 소스에 구현한다면 이미 컴파일된 소스에서 어디가 인라인 함수인지 알 수가 없기 때문이다.

'프로그래밍 > C++' 카테고리의 다른 글

후위 반환 형식 trailing return type/ suffix return type  (0) 2017.10.08
함수를 못 쓰게 하기  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08
디폴트 파라미터  (0) 2017.10.08
printf 형식지정자  (0) 2017.10.03

C와 달리 C++은 함수 오버로딩을 지원한다. 


함수 오버로딩은 함수 인자를 통해 동일한 이름의 함수를 구분하게 해준다.

함수 리턴 타입으로는 오버로딩이 되지 않는데, 함수를 부를 때 리턴값으로는 구분이 되지 않기 때문이다.


오버로딩 코드의 어셈블러 코드를 보면, 오버로딩은 결국 인자에 따라 컴파일러가 다른 이름의 함수를 여럿 생성하는 것이다.


예시 코드



아래는 어셈블리 코드이다.

보면 foo(int)는 fooi로, foo(double)은 food로 생성한 것이다. 

그리고 각각 아래에서 호출하고 있는 것이 보인다.


.file "practice.cpp"

.text

.globl _Z3fooi

.def _Z3fooi; .scl 2; .type 32; .endef

.seh_proc _Z3fooi

_Z3fooi:

.LFB0:

pushq %rbp

.seh_pushreg %rbp

movq %rsp, %rbp

.seh_setframe %rbp, 0

.seh_endprologue

movl %ecx, 16(%rbp)

movl $0, %eax

popq %rbp

ret

.seh_endproc

.globl _Z3food

.def _Z3food; .scl 2; .type 32; .endef

.seh_proc _Z3food

_Z3food:

.LFB1:

pushq %rbp

.seh_pushreg %rbp

movq %rsp, %rbp

.seh_setframe %rbp, 0

.seh_endprologue

movsd %xmm0, 16(%rbp)

movl $0, %eax

popq %rbp

ret

.seh_endproc

.def __main; .scl 2; .type 32; .endef

.globl main

.def main; .scl 2; .type 32; .endef

.seh_proc main

main:

.LFB2:

pushq %rbp

.seh_pushreg %rbp

movq %rsp, %rbp

.seh_setframe %rbp, 0

subq $32, %rsp

.seh_stackalloc 32

.seh_endprologue

call __main

movl $1, %ecx

call _Z3fooi

movq .LC0(%rip), %rax

movq %rax, %xmm0

call _Z3food

movl $0, %eax

addq $32, %rsp

popq %rbp

ret

.seh_endproc

.section .rdata,"dr"

.align 8

.LC0:

.long -1717986918

.long 1072798105

.ident "GCC: (GNU) 7.1.0"



'프로그래밍 > C++' 카테고리의 다른 글

함수를 못 쓰게 하기  (0) 2017.10.08
인라인 함수  (0) 2017.10.08
디폴트 파라미터  (0) 2017.10.08
printf 형식지정자  (0) 2017.10.03
표준 입력 cin  (0) 2017.08.06

C++에서는 아래와 같이 디폴트 파라미터를 줄 수 있다.



이때 몇 가지 주의사항이 있다.



1. 디폴트 파라미터는 뒤에서부터 줘야 한다.


즉, int foo(x, y = 0, z = 0) 은 되지만 int foo(x = 0, y, z = 0) 은 에러다.


뒤의 방식으로 썼을 경우 foo(1, 1)이라고 썼을 때 x가 생략된 것인지 z가 생략된 것인지 알 수 없다.



2. 선언부와 구현부가 나뉘어져 있을 경우 "선언부"에만 넣어야 한다.


만일 둘 다 디폴트 파라미터를 입력하면 컴파일 에러가 발생한다.


구현부에만 표기하면 디폴트 파라미터를 사용할 수 없게 된다.


외우기보단 이유를 생각해보면 되는데, 구현부는 소스코드에 있기에 미리 컴파일 되어 있으면 컴파일러가 확인할 수 없기에 헤더 파일의 선언부만 컴파일러가 확인할 수 있다. 따라서 구현부에만 넣어 놓은 것은 컴파일 시점에 영향을 미칠 수 없다.

'프로그래밍 > C++' 카테고리의 다른 글

인라인 함수  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08
printf 형식지정자  (0) 2017.10.03
표준 입력 cin  (0) 2017.08.06
표준 출력 cout  (0) 2017.08.06

printf의 기능 중 몰랐던 것들을 정리한다.


1. Width field을 이용해 loop 없이 공백 입력하기

printf format 중 *는 폭을 지정하는데, 이를 이용해서 가변 길이의 공백을 loop문 없이 입력할 수 있다.


printf("%*c", n, ' '); <= 변수 n에 0보다 큰 값을 넣으면 그 만큼 공백을 넣는다.


유사하게 %*s를 이용해도 결과는 같다.

printf("%*s", n, " ");


2. Precision field

%.*s 는 최대 아웃풋 길이를 지정해줄 수 있다.

printf("%.*s", n, buf); <= buf를 출력하되, 최대 n 길이만큼만 출력한다.


3. %n

printf 의 형식 지정자 중 유일하게 화면에 출력하는 것이 아닌 parmeter로 받은 포인터에 "지금까지 출력한 문자 개수"를 입력한다.

printf("100%n", p); <= int* p에 지금까지 100 세 글자를 입력했으므로 3을 입력한다.


4. printf(변수명)

printf에 꼭 printf("문자열", 인수1, 인수2, ...) 이렇게 하지 않고 변수 하나만 넘길 수도 있다.

이때 변수에 format specifier (%d, %n)등을 이용하면 printf에 인자가 모자라게 되므로, 보안 문제가 발생하게 되니 유의한다.





참고한 링크

https://en.wikipedia.org/wiki/Printf_format_string#Width_field

https://stackoverflow.com/questions/25609437/print-number-of-spaces-using-printf-in-c

https://stackoverflow.com/questions/18526978/s-format-specifier-in-printf-statement-in-c

https://www.coursera.org/learn/software-security (3, 4번 항목)

'프로그래밍 > C++' 카테고리의 다른 글

인라인 함수  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08
디폴트 파라미터  (0) 2017.10.08
표준 입력 cin  (0) 2017.08.06
표준 출력 cout  (0) 2017.08.06

C언어에서 표준 입력 함수 scanf를 썼듯이, C++에서는 cin을 사용한다.



cin은 scanf 와 달리 변수와 입력이 맞지 않으면 입력이 되지 않고, cin 의 return 값으로 체크할 수 있다.


출력 결과

k <- 입력

107

3 <- 입력

3

2 <- 입력

2

k <- 입력


scanf로는 int 형 변수에 char가 들어가지만, cin으로는 들어가지도 않고 cin이 false를 retrun한다. 유사하게 cin.fail() 함수는 입력 실패시 true를 리턴한다.

cin.clear() 는 이 에러 플래그를 지우는 역할을 한다.


cin 과 string 변수


cin >> string 변수를 할 경우 띄어쓰기 전 까지만 들어가게 된다. 따라서 띄어쓰기를 포함한 문장 한 줄을 넣고 싶다면 getline(cin, string 변수) 를 이용해야 한다.



출력 결과

Hello world again! <- 입력 문자열

str1: Hello

str2:  world again! 


이때 말한 대로 getline을 이용할 경우 띄어쓰기를 포함하여 string 변수에 입력이 되지만, 처음에 입력한 "Hello world again!"에서 str1 에 들어간 이후부터 자동으로 입력이 되어 버린다. 이를 막기 위해서는 C에서 fflush 처럼 입력버퍼를 비워줄 필요가 있다.


cin.ignore(int n, char c)는 n byte 만큼 또는 c 문자를 만날때까지 버퍼를 지운다.



Hello world again! <- 입력

str1: Hello

Hello world again! <- 입력

str2: Hello world again! 



'프로그래밍 > C++' 카테고리의 다른 글

인라인 함수  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08
디폴트 파라미터  (0) 2017.10.08
printf 형식지정자  (0) 2017.10.03
표준 출력 cout  (0) 2017.08.06

C에서의 표준 출력 printf가 있었듯이, C++에서는 표준 출력 cout이 있다.

cout은 표준입출력 iostream의 namespace std에 정의되어 있으며, 출력하고 싶은 내용을 << 연산자로 넣어주듯이 입력하면 화면에 출력한다. << 연산자로 출력이 가능한 것은 클래스에서 연산자 오버로딩을 해서 그런데, 직접 cout 클래스를 만들어보면 이해할 수 있다. 여기서는 cout을 사용하는 법만 다룬다.



printf는 변수 내용을 출력할 때 변수 자료형에 따라 %c, %f, %d 등을 맞춰서 써야 오류가 일어나지 않았지만, cout은 자료형을 신경 쓰지 않고 << 를 통해 넣어주면 자료형에 맞게 출력할 수 있다.



printf에서 출력 시 진법이나 자리수를 조정할 수 있듯이, cout에서도 조정 가능한 데 다소 번거롭다.


std::oct, std::dec, std::hex

cout에 << 로 입력하여 다음 출력할 변수의 형태를 변화시킬 수 있다.



width를 통해 최소 너비를 정하고, fill(char) 를 통해 최소 너비에 빈 공간을 채울 문자를 지정한다.
이때 std::left를 cout에 넣으면 숫자를 왼쪽으로 맞추고, std::right를 cout에 넣으면 숫자를 오른쪽부터 맞춘다.


출력결과

    32

32

123341

3123kkkkkkkkkkk

xxxxxxxxxxx1234



비트마스크 ios_base::fmtflags 를 입력하여 원하는 설정을 세팅할 수 있다. 비트마스크이므로 여러 설정을 동시에 하려면 bit or 연산자 | 를 사용한다.



출력결과

100 74

      0x64 0x4a 


ios_base::setf


이 함수도 flags와 비슷하게 원하는 설정을 세팅하는데 사용에 약간 차이가 있다.

setf는 두 가지로 오버로딩 되어있는데, 각각 의미하는 바가 다르다.

1. fmtflags setf (fmtflags fmtfl);

이것은 현재 설정된 플래그들 (flags() 함수의 출력값으로 알 수 있다.) 에 추가로 fmtfl을 설정한다. 즉, flags(fmtfl | flags() ) 이 된다.

2. fmtflags setf (fmtflags fmtfl, fmtflags mask);

이것은 mask와 fmtfl에 동시에 설정된 설정들만 적용하고, 동시에 적용되지 않은 설정들은 clear한다. 즉, flags( (fmtfl & mask) | (flags() & ~mask() ) 이 된다.


개인적으로 출력 형식을 바꿔야 할 경우에나 여러 변수 사이에 문자열을 끼워넣어야 하는 경우 오히려 printf 가 더 간단해서 printf를 사용한다.


'프로그래밍 > C++' 카테고리의 다른 글

인라인 함수  (0) 2017.10.08
함수 오버로딩  (0) 2017.10.08
디폴트 파라미터  (0) 2017.10.08
printf 형식지정자  (0) 2017.10.03
표준 입력 cin  (0) 2017.08.06

+ Recent posts