이제부터 C랑 겹치는 내용이 좀 나오지싶은데,
잘 알고있는거라 굳이 언급할만한게 아니면 따로 정리하진 않아야지
OOP의 본질은 나만의 data type을 만들고 확장하는 것이다.
하지만 그 전에 기본 built-in data type을 알아야 한다.
built-in types은 두 종류로 나뉜다.
1. fundamental types (이 chapter에서 다룸)
2. compound types (array, string, pointer, structure 등 chapter 4에서 다룸)
정보를 저장하기 위해 알아야하는 특성
1. 어디 저장했는지
2. 어떤 값이 저장됐는지
3. 어떤 종류의 informantion이 저장됐는지(크기때문에 그런듯)
int braincount = 5;
라는 statement에선, int형을 저장하기 충분한 공간을 memory에 할당하고, 그 위치를 기억하고, value 5를 그 location에 저장하는 과정이 일어난다.
(별거 아닌거같은데 어셈블리어 좀 배우고 보니 색다르게? 보이네)
(이 statement가 어디에 저장됐는지 우리에게 알려주진 않지만, program이 알아서 keep track)
길어도 괜찮으니 좀 의미있는 이름을 지어라 (C++은 길이에 제한을 두지 않는다. 물론 platform에 따라 제한이 있을 수 있음)
(ANSI C에선 63개까지만 구분되도록 했었음)
naming rule은 C와 같음(문자, 숫자, underscore 올 수 있고, 숫자는 처음에 못온다.)
추가로, 'underscore 2개(__
)'로 시작하거나 'underscore 1개+대문자' 는 implementation에서 사용하도록 예약돼있다.
'underscore 1개(_
)'로 시작하는건 implementation이 global identifier로 사용하도록 예약돼있다.
(마지막 추가로 말한 규칙들은 지키지 않아도 compiler error는 아니지만(naming 규칙을 지켰으므로 error는 아닌 것이다, implementation이 예약을 한게 문제가 되는거지) UB이다.)
(naming scheme은 말이 많은데, 그냥 본인 style에 맞게 정확하고 일관되게 기술하면 된다.
type이나 contents를 이름에 적어주기도 한다. ex.int nMyWeight
or int intMyWeight
)
char
, short
, int
, long
, long long
(C++11)
signed
or unsigned
short
, int
, and long long
Integer Types모든 computer designs을 만족하는 type들의 따른 특정 bit수가 없기때문에, standard에선 C처럼 minimum size만 정의한다.
short
는 최소 16 bitsint
는 short
보다 크거나 같다.long
은 최소 32 bits이고, int
보다 크거나 같다.long long
은 최소 64 bits이고, long
보다 크거나 같다.unsigned
만 있으면 unsigned int
unsigned는 값 범위 넘어가면 다시 돌아가는걸 보장하지만, signed가 초과할 수 있도록 보장하진 않는다.
Bits and Bytes
computer memory의 기본 unit은 두말할 필요없이 bit이다.
byte는 주로 memory의 8-bit unit을 말한다.
하지만 이는 memory 크기 얘기할때고,
C++에서 byte는 해당 implementation의 basic character set을 충족시킬 수 있는 최소 bit 수이다.
그리고 char
는 해당 bit 수를 가지도록 한다.
미국에선 ASCII나 EBCDIC set을 주로 쓰는데, 얘네는 8bits로 모두 만들 수 있다. 그래서 C++에서도 byte는 주로 8 bits이긴 하다.
하지만 international programming에서 unicode 같은거 쓰게되면 16-bit byte나 32-bit byte가 될 수도 있다.
(몇몇은 8-bit byte를 아예 "octet"이라고 부름)
climits
혹은 limits.h
헤더를 이용해 int형 type의 범위를 알 수 있다.
CHAR_BIT
를 통해 byte가 몇개의 bit로 이루어졌는지 알 수 있다.
sizeof
Operator and the climits
Header File <<sizeof
operator 사용할때 type name이면 괄호 필수이지만, variable name이면 괄호는 선택이다.
sizeof (int)
sizeof n_short
: n_short는 variable name
#define
으로 symbolic constants를 지정하는건 C relic이고,
C++에서는 주로 const
를 이용해 symbolic constants를 만들기때문에 #define
을 많이 쓸일은 없다.
(const
에 관해선 뒤에 얘기. C랑은 좀 다르게 처리되나봄)
int owls = 101;
: traditional C initialization
int wrens (432);
: C++ syntax (C에선 적용안됨)
초기값 알고있다면 initialize 하는게 좋다.
C++98
int hamburgers = {24};
이렇게 array나 structure에 쓰이던 initializer형태를 일반 변수에도 쓸 수 있게 함.
C++11
int emus{7};
int rheas = {12};
int rocs = {}; //0으로 set
int dls{} //0으로 set
이렇게 =
기호 없이도 작동하도록 했다.
참고로 이 기호를 사용하면 narrow assignment 금지
왜 이것저것 표현 방법을 추가했지?
novice가 쉽게 사용하도록 하기 위해서이다.
원래 C++은 initialization 형태가 class variable에 적용할때랑 일반적인 곳에 적용할때랑 달랐다.
이를 비슷하게 하기위해 일반 변수에도 괄호를 사용할 수 있도록 했고,
C++11에선 모든 type에 brace syntax를 사용할 수 잇도록 했다.
대게 int
는 해당 computer에서 가장 자연스러운 integer size로 set된다.
가장 효율적으로 다룰 수 있단 소리다.
따라서 별다른 이유 없으면 int쓰면 된다.
큰 숫자면 `long`으로 처리해도 좋다.
왜냐하면 내 컴퓨터에서는 `int`에 넣을 수 있더라도, 다른 컴퓨터로 옮겼을 경우도 생각해야한다.
같은 이유로, 공간절약이 중요하다면 내 컴퓨터에서 `short`와 `int` size가 같더라도 `short`를 써야한다.
이건 source code 단계에서 하는 얘기지 싶네
실행파일은 다른 bit에선 안돌아가니까(다른 OS면 당연히 더 안돌아가고)
integer literal 표현법
첫번째 digit이 0-9면 base 10
첫번째 digit이 0이고, 두번째 digit이 1-7이면 base 8
처음 두 digit이 0x, 0X이면 base 16
얘네는 그냥 편의를 위해 표현만 다르다는걸 알고있어야한다. 컴퓨터엔 (같은 수는) 2진수로 저장된다.
cout
은 기본적으로 decimal form으로 출력
hex
, oct
manipulator를 이용해 출력 form을 변경할 수 있다.
cout << hex
라고 하면 이 다음부터 숫자는 hexadecimal로 출력된다.
std
namespace를 사용한다고 적어뒀으면 hex
를 변수 이름으로 사용하지 못한다.
그러지않고 std::hex
형식으로 사용하면 hex
를 변수 이름으로 사용해도 괜찮다.
constant는 기본적으로 int
에 저장
suffix가 있는 경우,
그에 맞는 type에 저장(문자 l
suffix는 숫자 1
로 보일 수 있으니 L
권장)
size가 int
에 맞지 않는 경우(without suffix),
10진수로 표현된 숫자라면 int
, long
, long long
의 순서로 들어갈 수 있는 가장 작은 type에 들어가고,
8진수나 16진수라면 int
, unsigned int
, long
, unsigned long
, long long
, unsigned long long
의 순서로 들어갈 수 있는 가장 작은 type에 들어간다.
10진수와 8/16진수를 저장하는데 차이가 있는 이유는,
8/16진수는 주로 memory address를 표현하기 때문이다.
주소를 표현하는데는 unsigned가 적합하므로 저장 방식에 차이가 있다.
16-bit address를 표현하는데 long보단 unsigned int가 더 적절하다.
char
Type(Characters and Small Integers)
문자도 결국 숫자로 변환돼 저장되므로 char
type은 또 다른 integer
type이다.
(그러므로 short
보다 작은 숫자를 다룰거면 char
이용해도 됨. 물론 당연히 character 다루는데 더 많이 쓰이긴 함.)
host system이 사용하는 character set을 사용한다. 예를들어 IBM mainframe은 EBCDIC("eb-se-dik"이라 발음)
int랑 다르게 default가 signed
인지 unsigned
인지 정해진게 없다.
implementation마다 다르므로 이게 중요하다면(숫자로 사용하거나 한다면) 정확히 명시해라.
char ch;
cin >> ch;
cout << ch;
를 하면 ch
는 문자 "형태"로 입력되고 출력된다.
char
type이면 cin
과 cout
이 그렇게 되도록 기능하는 것이다.
int
면 숫자 그대로 출력됨, type에 따라 cout
이 display style을 결정한다.
마찬가지로 cin
도, cin >> ch
에서 ch
가 int라고 해보자.
5
라고 입력하면 숫자 5가 그대로 들어가지만,
ch
가 char이면, 실제론 숫자 53이 저장되는 것이다.
cout.put(ch);
: single character ch
를 출력한다.
cout.put()
cout.put()
은 member function이다. (OOP 개념)
class는 data를 (1)어떻게 표현할지, (2)어떻게 다룰지 를 정의하는데,
member 함수는 class에 속해서 class data를 (2)어떻게 다룰지 를 정의(?)한 것이다.
ostream
class에는 put()
이라는 member function이 있는 것이고, 이 함수를 해당 class의 object인 cout
에 사용하는 것이다.
이때 membership operator라고 불리는 period(.
)를 같이 사용해줘야 한다.
cout.put()
필요있나?cout
은 character variable은 문자로 잘 출력했지만, character constant는 숫자로 출력했다.(cout << 'M';
이라고 하면 숫자로 출력됐단 소리)cout
이 character variable과 constant를 다르게 봐서 생긴 문제이다.(현재는 single-character constant를 int
가 아닌 char
에 잘 저장한다.)cout.put('M');
의 형태로 출력해야했다.char
Literalschar
Literal을 표현하는 방법
'a'
이런 식으로 single quote 안에 문자를 넣어서 표현
: numeric code가 달라도 적용된다.(ASCII와 EBCDIC의 code는 다르지만 저렇게 표현하면 두 군데서 적용 가능)
keyboard로 표현할 수 없는 문자 혹은 표현되더라도 특별한 의미가 있는 문자는 escape sequence code(p.85 Table 3.2)를 사용해서 표현
: 일반 문자인듯이 사용한다. 얘도 마찬가지로 numeric code 달라도 적용된다.
escape sequence는 teletype을 사용하던때에 만들어진거라 요즘 컴퓨터에선 지원이 잘 안될수도 있다.
(예를들어 alarm character를 줘도 system이 조용하다거나)
문자말고 해당 character set의 8/16진수 코드에 맞게 작성해도 된다.
numeric/symbolic escape sequnce 중 뭐가 더 낫나?
: 선택할 수 있다면, symbolic code를 써라.
numeric은 특정 character set에만 특정되지만, symbolic은 그렇지도않고 읽기도 쉽다.
ex)
cout << "Enter your code: _____\b\b\b\b\b";
cin >> code;
이런 식으로 \b
를 이용하면 저 부분이 지워지면서 입력됨.(system마다 다르게 작동하긴함. \b
해버리면 커서만 이동하는게 아니라 underscore가 지워지기도하고)
basic source character set : source code 내에서 쓰일 수 있는 character들 (영문, 숫자, {
, =
같은 기호 등)
basic execution character set : program 실행 중에 사용될 수 있는 character들 (위 set에 backspace나 alert가 추가됨)
C++ 표준에선 extended source character set이나 extended execution character set을 implementation이 제공하도록 허용
그래서 국가마다 다양한 chracter set이 추가될 수 있는데, C++에선 특정 keyboard와 독립적으로 쓰일 수 있게 universal character name을 제공한다.
universal character name
\u
뒤에 4개의 16진수 digit
\U
뒤에 8개의 16진수 digit
둘 중 하나로 표현한다.
extended character set을 지원하는 implementation이라면 universal character name을 identifiers, character constants, strings에서 쓸 수 있다.
universal charcter "code"가 아니라 "name"이라고 부른다.
\u00F6 이라고 적으면 이 코드 그대로 저장되느게 아니기때문이다.
encoding에 따라 내부에 저장되는건 달라질 수 있다.
그래서 같은 name을 쓰면 다른 encoding 방식이여도 잘 작동하는 것이다.
wchar_t
C++은 8-bit에 들어맞지 않는 large character set을 여러 방법으로 다룬다.
1. large set이 해당 implementation의 basic character set이라면, compiler 제작자가 char
을 16-bit byte 이상으로 설계할 수 있다.
2. implmentation이 small basic set과 large extended set을 지원한다면, 8-bit char
이 basic character set을 표현하고, wchar_t
type으로 extended character set을 표현한다.
wchar_t
해당 시스템의 가장 큰 extended character set을 표현하기 충분한 공간
integer type 중 하나와 같은 크기를 가진다: 그렇게 바탕이 되는 type을 underlying type 이라고 함.
char처럼 signed나 unsigned로 지정하진 못한다.
cin
이나 cout
은 char
에 맞춰져있어서 wchar_t
에 대해선 제대로 기능하지 않는다.
그래서 wcin
, wcout
을 써야함.
wide-character constant나 string : prefix L
char16_t
and char32_t
(new C++11 types)
(wchar_t
만으론 충분하지 않다는게 시간 지나며 확인됨)
정해진 size와 signedness가 있으면 더 유용한 경우가 있다.
이를 위해 char16_t
와 char32_t
를 만듦(wchar_t
는 implementation마다 다르니)
둘 다 unsigned
이고 bit 수는 뒤에 숫자
char16_t
character나 string constant를 나타내기 위해 u
prefix 사용
char32_t
character나 stirng constant를 나타내기 위해 U
prefix 사용
둘 다 underlying type을 가진다.
(wchar_t
와 다른 점은 얘넨 bit수와 unsigned가 정해져있으니 그거에 따라 맞는 type이 underlying type이 되겠지)
bool
TypeC++은 nonzero는 true로 zero는 false로 해석
bool
type
true
predefined literal
false
predefined literal
true, false도 int같은 numeric value로 각각 0, 1로 바뀔 수 있고,
반대로 numeric이나 pointer value가 bool로 바뀔 수도 있다.
const
Qualifierconst
qualifier를 사용할때 보통 첫글자를 대문자로하거나 모두 대문자로 하기도하고, 아니면 앞에 문자 k
를 붙이기도한다.
값 수정이 안되므로, initialize 필요 (static 과는 다르게 변수로 초기화 가능)
#define
방식보다 낫다.(책에서 계속 define대신 const 쓰라고 하네)
1. type 정의 가능
2. scoping rule 따른다
3. array나 structure 같은 정교한 type에도 적용 가능
const의 scope rule에서 ansi C와 차이가 있다는데 그건 chapter9에서 설명
그리고 C++의 const 변수는 배열 길이 명시하는데 사용될 수 있다고 한다.
(C도 VLA로 치면 할 순 있는데, 얘는 아예 일반적인 배열 말하는듯.)
(아래 첫번째 link 보니 C++에선 const 사용시 아예 constant expression임)
C와 C++ const 차이점
C와 C++ const 처리 차이점
C++엔 VLA가 없구만,, 그 이유
(integer에 비해 훨씬 크거나 작은 수 표현 가능)
(1) decimal point : I/O할때는 지역에 맞는 decimal point 사용해도 OK, code내에선 무조건 .
으로 써야함.
(2) E notation : 숫자랑 띄어쓰면 안됨. 8.33E-4
식으로 작은 수도 표현
float
doubl
long double
floating-point constant는 기본적으로 double
float
-> f
, F
suffix
long double
-> l
, L
suffix
integer보단 크고 작은 수 표현할 수 있지만,
integer operation에 비해 좀 느리다.
precision을 넘어가서 표현할 순 없다.(구분이 안됨)
floating-point type과 integral(integer) type 전체를 arithmetic type이라고 함.
floating-point type에는 float, double, long double이 있고,
integral(integer) type에는 signed integer type과 unsigned integer type, 그리고 bool, char, wchar_t가 있다.
signed와 unsigned integer type은 뭐 말안해도 알테니..
초등학교때 4칙연산이 쉬웠던 것처럼, 컴퓨터에게도 간단한 연산들이 있다.
addition, substraction, multiplication, division, modulus (어셈블리어에서도 정의된 것들이네)
modulus 연산 : 둘 다 int여야함. operands 중 하나가 negative라면 를 만족하도록 결과값의 부호가 결정된다.
(int division과 함께 양을 나눠야할때 주로 쓰인다. pound 무게를 stone 단위로 바꾼다던가)
한 operand에 두개의 operator가 적용되면 -> precedence
precedence가 같다면 -> associativity
두 operator가 한 operand를 공유해야만 precedence와 associativity로 해결 가능
20*5 + 24*6;
같은 경우 앞의 곱셈과 뒤의 곱셈 중 누가 먼저 계산될지 모른다.
(implementation defined)
operands 종류에 따라 divison operator도 종류와 행동이 나뉜다.
int
division, float
division, double
division, ...
(어셈에서 fdiv, idiv, div 연산이 다 따로있다. 얘네가 그걸 그대로 쓰는진 모르겠으나..)
이렇게 같은 symbol로 하나 이상의 operation을 표현하는걸 operator overloading이라고 한다.
(중요한 OOP 특징. operator overloading이 OOP에만 있는건 아니지만, user defined class에서도 operator overloading 허용하기때문에 중요 특징이라는거 같다.)
automatic type conversion이 일어나는 경우
1. assign
2. expression
3. argument
type이 맞지 않을때 (C에선 return type인 경우도 그랬는데, 얘도 나중에 설명하려나)
더 큰 range로 assign되는건 주로 잘 된다. 아래의 경우는 문제가 생길 수 있다.(이외에도 뭐 signed unsigned 라거나.. 안전하게 하자 그냥)
Conversion Type | Potential Problems |
---|---|
큰 floating type을 작은 floating type에 | precision을 잃을 수 있다. range를 벗어나면 Undefined |
Floating type을 integer type에 | 소숫점 뒷부분 잃는다. range를 벗어나면 Undefined |
큰 integer type을 작은 integer type에 | 범위를 벗어날 수 있다. 그러면 주로 low-order byte만 복사된다 |
유효숫자가 많은 integer를 floting type에 | 유효숫자 개수가 precision을 넘어가면, 정확하게 저장되지 않을 수 있다. |
(마지막 경우, float이 숫자 범위는 int보다 더 큰값을 나타낼 수 있지만 유효숫자 부분은 잘 고려해야됨)
bool
에 assign할때 0은 false
로, nonzero는 true
로 convert됨
{}
썼을때 conversion (C++11) <<C++11에선 {}
를 사용한 initialization을 list-initialization이라고 한다.
()
를 쓰거나 그냥 일반적으로 assign할때는 위처럼 되지만, {}
를 쓰면 좀 더 제한적이다.
narrowing 금지. assigned value를 나타낼 수 없으면 안된다.
ex.
floating type -> integer type : X (소숫점부분이 0이거나 해도 안된다.)
'변수'도 얼마나 큰지 당장 알 수 없으므로 narrow를 판단할 수 없어서 일단 char c = {x};
꼴도 안된다고(error) 함.(단, x가 const
로 선언됐으면 가능)
(해보니 또 잘 되긴하는데 표준 찾아보니 안된다고 정의돼있다.)
몇몇 type은 일단 자동 변환된다. integral promotion
bool
, char
, unsigned char
, signed char
, short
-> int
(int
가 short
보다 크다면) unsigned short
-> unsgined int
wchar_t
-> int
, unsigned int
, long
, unsigned long
(이 중 모든 범위를 수용할 수 있는 가장 작은 곳에 들어감)
ex) short c = a+b; //a와 b는 short
: 이걸 실행하면 a와 b가 int로 바꼈다가 계산 후 다시 short로 바뀌는 것이다.
좀 돌아가는 것 같지만, int는 해당 computer에 가장 자연스러운 가장 빠르게 계산할 수 있는 type이므로 이게 맞다.
나머지들은 다른 type과 expression으로 묶이면 변환된다.
이땐 작은 것이 큰 것으로 변환된다. (자세한 변환 방식 list는 p. 106에 있음. rank 관련 부분은 좀 아래에 표시해둠)
prototype을 통해 type을 체크
(long) a;
long (a);
두가지 형식이 있음. (C에선 전자만 허용)
아래는 함수호출같이 보이게 하는 효과
Stroustrup(C++ 창시자)님께서 기존 C의 type cast는 제한사항이 딱히 없어 위험하다고 생각
그래서 다음과 같은 type casting operator 추가(기존 casting보단 제한적임)
static_cast<typeName> (value)
auto
Declarations (in C++11)compiler가 initialization value의 type을 추론하도록하기위해 auto
를 쓴다.
본래 C에서 auto는 storage class를 정의하기 위한 것으로,
block 내부에서 선언된 variable에만 쓰일 수 있었다.
auto를 적용하면 automatic storage duration, block scope, no linkage가 되는데,
이미 block내부에서 선언된 variable은 해당 특징을 가지므로 auto는 쓰일 일이 거의 없었다.
그래서 이 의미를 redefine한 것이다.
auto x = 1.5;
하면 x는 자동으로 double이 됨.
잘못쓰일 수 있으니 조심해야한다. ex) double을 의도했는데, auto x = 0;
라고 할 수 있음.
STL의 복잡한 type 다룰때 유용
C++11 이후론 이전의 의미로는 사용하지 못한다.
standard를 만들때 새로운 keyword를 추가하는 것은 기존 code와 호환문제로 좀 꺼려진다.
그렇기 때문에 새로운 것을 소개하기보단 기존에 있던 keyword이고 거의 쓰이지 않았던 auto를 가져온 것
C++에서 char
는 system's basic character set을 모두 표현할 수 있도록, wchar_t
는 system's extended character set을 모두 표현할 수 있도록 정의한다.
type도 많고, conversion rule도 복잡하고 해서 너무 과하다고 생각할 수 있지만, 다 필요한 것이다..
하다보면 알게 됨