[C++ Primer] Chapter 2 Variables and Basic Types
summary of C++ Primer chapter 2
- 타입은 프로그램에서 데이터와 연산의 의미를 결정한다.
2.1 기본 내장 타입
- C++에서 정의하는 기본 타입에는 산술 타입과
void
라는 특별한 타입이 있다.- 산술 타입 - 문자, 정수, 부울값, 부동소수점
void
타입 - 연관된 값이 없고, 제한된 상황에서만 사용 가능
2.1.1 산술 타입
- 산술 타입
- 정수 타입 - 문자와 부울 타입을 포함한다.
- 부동소수점 타입
- 비트 수로 나타내는 산술 타입의 크기는 시스템에 따라 다르다.
bool
타입은ture
와false
의 진리 값을 나타낸다.- 부동소수점 타입은 단정도, 배정도, 확장 정밀도 값을 나타낸다.
- 부호 있는 타입고 부호 없는 타입
bool
과 확장 문자 탕비을 제외한 정수 타입은 부호 있는 타입이거나 부호 없는 타입이다.- 기본 문자 타입은
char, signed char, unsigned char
세가지로 구분 가능하다.
- 사용할 타입 결정하기
- 음수가 될 수 없으면 부호 없는 타입을 사용한다.
- 정수에는
int
를 사용한다. - 산술 표현식에는 일반적인
char
나bool
을 쓰지 않는다. - 부동 소수점 연산에는
double
을 주로 쓴다.
2.1.2 타입 변환
- 타입 변환은 어떤 타입인 객체를 그와는 다른 타입을 기대하는 곳에 사용할 때 자동으로 일어난다.
- 부호 있는 타입 객체에 범위를 벗어난 값을 대입하면 결과는 미정의이다. → 미정의는 하지 말자.
- 부호 없는 타입을 포함한 표현식
- 피 연산작 하나 또는 둘 모두가 부호 없는 타입이든 그렇지 않든, 부호 없는 타입에서 값을 뺄 때는 결과가 음수가 아닌지 확인해야 한다.
1.2.3 상수
- 숫자와 같은 값은 그 값 자체로 명확하므로 상수라고 한다.
- 정수와 부동소수점 상수
- 0으로 시작하면 8진수, 0x나 0X로 시작하면 16진수
- 문자열과 문자열 상수
- 작은 따옴표로 둘러싼 문자는
char
타입 상수이고, 큰따옴표로 둘러싼 문자는 문자열 상수이다. 문자열 상수의 타입은char
배열이다. - 컴파일러에서는 모든 문자열 상수에 널 문자를 추가한다.
- 서로 이웃하며 공백 문자, 탭, 줄바꿈 문자로만 나뉜 두 문자열 상수는 하나로 합칠 수 있다.
- 작은 따옴표로 둘러싼 문자는
- 확장 문자열
- 출력할 수 없는 문자열은 확장 문자열을 사용해 나타낼 수 있다. 백 슬래시로 시작한다.
- 상수 타입 지정
- 접두어와 접미어를 통해 상수의 타입을 지정할 수 있다.
- 부울과 상수 포인터
2.2 변수
- 변수는 프로그램에서 조작할 수 있는 명명한 저장 공간이다.
- 변수를 객체라고도 한다.
2.2.1 변수 정의
1
int sum = 0, value, units_sold = 0;
- 변수의 정의 - 타입 지정자로 시작하고 변수 이름을 쉼표로 구분해 하나 이상 쓴 다음 세미콜론으로 마친다.
- 객체 - 이 책에서는 타입이 있는 데이터 영역
- 초기화
- 객체를 만들면서 값을 지정하는 것
- 한 정의문 내에서 먼저 정의한 변수 값을 사용해 다른 변수를 초기화할 수 있다.
- 초기화와 대입 연산은 다른 연산자이다. → 초기화는 변수를 만들 때 값을 지정하는 것이고 대입은 객체의 현재 값을 지우고 새로운 값으로 바꾸는 것이다.
1
2
3
4
int a = 0;
int a = {0};
int a{0};
int a(0);
- 목록 초기화
- 이러한 중괄호로 초기화하는 것을 목록 초기화라고 한다.
- 초기 값 때문에 데이터 손실이 생길 수 있으면 컴파일러에서는 내장 타입 변수에 초기화 목록을 사용을 허용하지 않는다.
- 기본 초기화
- 초기 값 없이 변수를 정의하면 그 변수는 기본 초기화된다.
- 하지만 함수 안에서 정의한 내장 타입 변수는 초기화하지 않는다. → 미정의이다. → 오류이다.
- 클래스 대부분은 명시적으로 초기화 하지 않아도 객체를 정의할 수 있다. 하지만 어떤 클래스는 모든 객체를 명시적으로 초기화해야 한다. → 아니면 오류남
2.2.2 변수 선언과 정의
- C++은 분리 컴파일을 지원한다 ← 프로그램을 여러 파일로 나누고, 각각을 독립적으로 컴파일할 수 있다.
- 선언 - 프로그램에 이름을 알리는 것으로, 어딘가에 정의한 이름을 사용하려면 그 이름에 대한 선언을 포함한다.
- 정의 - 연관된 개체를 만든다.
extern
키워드를 사용하면 정의가 아닌 선언을 할 수 있다.
1
2
extern int i; // i를 선언하지만 정의하자 않는다.
int j; // j를 선언하면서 정의한다.
- 모든 내장 타입 객체는 초기화하길 권한다. 항상 해야 하는 것은 아니지만 하는 것이 좋다.
- 같은 변수를 여러 파일에서 쓰려면 그 변수를 오직 한 파일에서만 정의하고, 다른 파일에선는 그 변수에 대한 정의가 아닌 선언을 해야 한다.
- C++은 정적 타입 언어로, 컴파일 시점에서 타입을 검사한다.
2.2.3 식별자
- C++에서 식별자는 문자, 숫자, 밑줄 문자로 만들 수 있다. 숫자로 시작할 순 없다. 대소문자를 구별한다. 예약어는 식별자로 사용할 수 없다.
- 변수 이름 규칙
- 식별자는 그 자체로 의미를 나타내야 한다.
- 변수 이름은 보통 소문자로 쓴다.
- 클래스는 보통 대문자로 시작한다.
- 식별자를 여러 단어로 쓸 때에는 시각적으로 구분이 되도록한다. 스네이크 케이스나 캐맬 케이스로 쓴다.
2.2.4 이름 유효 범위
- 유효 범위(scope)는 프로그램에서 이름이 특별한 의미를 지니는 구역이며 C++에서는 대부분의 유효 범위는 중괄호로 구분한다. 같은 이름이더라도 유효범위가 다르면 다른 개체를 참조할 수 있다.
- 전역 유효 범위 (global scope) - 중괄호 밖에서 정의한 것
- 구역 유효 범위 (block scope) - 중괄호 영역 안에서 정의한 함수이다. for문 안에서 정의한 함수는 for문 안에서만 쓸 수 있다.
- 객체는 처음 사용하는 곳 가까이 정의하는 것이 좋다.
- 중첩된 유효 범위
- 포함된 유효범위를 내부 유효 범위(inner scope), 포함하는 유효 범위를 외부 유효 범위(outer scope)라고 한다.
- 내부 유효 범위에서 외부 유효 범위의 이름을 사용할 수 있다. 외부 유효 범위에서 선언한 이름을 내부 유효 범위에서 다시 정의할 수도 있다.
- 함수에서 사용하고 있거나 사용할 수도 있는 전역 변수와 같은 이름으로 지역 변수를 정의하는 것은 좋지 않다.
2.3 복합 타입
- 복합타입 - 다른 타입을 사용해 정의한 타입이다. 여럿이 있는데 그중 참조자와 포인터를 이 장에서 다룬다.
2.3.1 참조자
- 참조자는 객체에 별칭을 정의한다. 참조자로 참조하는 다른 타입이 곧 참조자 타입이다.
- 참조자 타입을 정의할 때는 선언자를
&이름
형식으로 쓴다. - 보통 변수를 초기화할 때는 초기 값을 생성하는 객체에 복사해 넣는다. 참조자를 정의할 때는 초기 값을 복사하지 않고 참조자를 초기화식에 결합한다. 참조자는 반드시 초기화해야 한다.
- 참조자는 별칭이다
- 참조자는 객체가 아니며, 이는 이미 존재하고 있는 객체에 대한 다른 이름일 뿐이다.
- 참조자 정의
2.3.2 포인터
- 포인터는 다른 타입을 가리키는 복합 타입이다.
- 참조자와 달리 포인터는 그 자체로 객체이다.
- 대입하거나 복사할 수 있으며, 포인터 하나가 생명 주기 동안 여러 다른 객체를 가리킬 수 있다.
- 초기화하지 않아도 된다. → 그러면 미정의 값을 가진다.
*이름
형식으로 쓴다,*
은 각 포인터 변수마다 반복해 써야한다.- 객체 주소 얻기
- 포인터는 다른 객체의 주소를 담고 있다. 객체의 주소는 주소연산자(
&
)를 통해 얻는다.
- 포인터는 다른 객체의 주소를 담고 있다. 객체의 주소는 주소연산자(
- 포인터 값
- 포인터에 저장하는 값인 주소는 다음 네 가지 상태 중 하나가 될 수 있다.
- 객체를 가리킬 수 있다.
- 객체의 마지막 요소 바름 다음 위치를 가리킬 수 있다.
- 어느 객체와도 결합하지 않았음을 나타내는 널 포인터일 수 있다.
- 유효하지 않을 수 있다. 위 3가지가 아닐 수 있다.
- 포인터에 저장하는 값인 주소는 다음 네 가지 상태 중 하나가 될 수 있다.
- 포인터를 사용해 객체에 접근하기
- 포인터로 객체를 가리키고 있으면 역참조 연산자(
*
)를 사용해 객체에 접근할 수 있다.
- 포인터로 객체를 가리키고 있으면 역참조 연산자(
- 널 포인터
- 어느 객체도 가리키지 않으므로 포인터를 사용하기 전에 널인지 확인하는 것이 좋다.
- 최신 C++프로그램에서는 NULL보다 nullptr을 쓰는 것이 좋다.
- 대입과 포인터
- 참조자는 객체가 아니다.
- 모든 포인터는 초기화해야한다.
- 다른 포인터 연산
- 포인터 값이 유효하면(0이 아니면) 조건문에 쓸 수 있다. 0이면 false이다. 0이 아니면 true이다
void*
포인터void*
포인터는 모든 객체의 주소를 담을 수 있는 특별한 포인터 타입이다. 가리키는 객체의 타입은 알 수 없다.- 일반적으로 메모리를 메모리로 다루기 위해 사용된다.
2.3.3 복합 타입 선언 이해하기
- 여러 변수를 정의하기
- 타입 변경자는 단일 문장에서 정의한 모든 변수에 적용하는 것이 아니다.
- 포인터에 대한 포인터
- 일반적으로 선언자에 적용할 수 있는 타입 변경자 수에는 제한이 없다.
- 포인터에 대한 참조자
- 참조자는 객체가 아니다 → 참조자에 대한 포인터는 없다.
- 포인터는 객체이다 → 포인터에 대한 참조자는 정의할 수 있다.
- 오른쪽에서 왼쪽으로 읽으면 쉽게 이해할 수 있다.
2.4 const
한정자
1
const int buf = 100;
- 변수의 타입을 const로 정의해서 값이 바뀌지 않도록 할 수 있다.
- 초기화와
const
- 객체를 바꿀 수 없는 연산만 사용가능 하다.
- 기본적으로
const
객체는 파일에 지역적이다.const
객체를 상수로 초기화한다면 컴파일 중에 그 변수를 모두 해당 값으로 변환한다.const
객체를 여러 파일에서 공유하려면 그 변수를extern
으로 정의해야한다.
2.4.1 const
에 대한 참조자
- 참조자를
const
타입 객체에 결합할 수 있다. - 보통의 참조자와 달리
const
에 대한 참조자를 사용해 해당 참조자와 결합한 객체를 바꿀 수 없다. const
의 참조자를 만들 때에는 참조자도const
를 붙여야한다.- 초기화와
const
에 대한 참조자const
에 대한 참조자는const
가 아닌 객체, 상수, 더 일반적인 표현식과 결합할 수 있다.- 아래 코드와 같이 컴파일러가 코드를 위에서 아래로 변경한다.
1
2
3
4
5
double dval = 3.14;
const int &ri = dval;
const int tmp = dval;
const int &ri = temp;
const
에 대한 참조자는const
가 아닌 객체를 참조할 수 있다.const
를 써서 만든 참조자는 값을 변경할 수 없다. 하지만 변수는 직접 변경할 수 있다.
2.4.2 포인터와 const
const
에 대한 포인터는 가리키는 객체를 바꿀 수 없다.const
에 대한 포인터에는const
객체의 주소만 저장할 수 있다.const
에 대한 포인터로const
가 아닌 객체를 가리킬 수 있다.const
에 대한 포인터로 객체를 가리키더라도 그 객체가 변경되지 않음을 보장하지 않는다.const
포인터- 다른 객체처럼
const
포인터는 초기화해야 하며 초기화한 후에는 담고있는 주소를 바꿀 수 없다. - 대상 객체를 바꿀 수 있는 지 여부는 알 수 없다.
- 다른 객체처럼
1
2
3
4
int errNum = 0;
int *const currErr = &errNum;
const double pi = 3.14159;
const double *const pip = π
2.4.3 상위 const
- 책의 용어 정리
- 상위
const
- 포인터 자체가const
임 - 하위
const
- 가리키는 것이const
임
- 상위
- 상위
const
는 객체를 복사할 때 무시한다 - 하위
const
는 객체를 복사할 때 영향을 미친다const
가 아닌 객체는const
객체로 변환할 수 있다. 그 반대는 아니다.
2.4.4 constexpr
과 상수 표현식
- 상수 표현식은 컴파일 중에 값을 평가할 수 있으며 그 값을 바꿀 수 없는 표현식이다.
1
2
3
4
const int max_files = 20; // O
const int limit = max_files + 1; // O
int staff_size = 27; // X
const int sz = get_size(); // X
- 위 코드와 같이 상수이고 컴파일러가 초기에 값을 알 수 있을 때가 상수 표현식이다.
constexpr
변수constexpr
선언을 사용해 변수가 상수 표현식인지 컴파일러에서 확인할 수 있다.constexpr
로 선언한 변수는 암시적으로const
이므로 상수표현식으로 초기화 해야한다.
1
2
3
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr int sz = size(); // size가 constexpr함수일 때만 성립
- 상수 타입
- 지금까지 사용한 타입중에 산술, 참조자, 포인터 타입이 산술 타입이다. 산술 타입이 아닌 것들로
constexpr
를 선언할 수 없다. - 포인터와 참조자 모두
constexpr
로 정의할 수 있지만 초기화하는 데 사용하는 객체는 엄격히 제한된다.
- 지금까지 사용한 타입중에 산술, 참조자, 포인터 타입이 산술 타입이다. 산술 타입이 아닌 것들로
- 포인터와
constexpr
constexpr
선언에 포인터를 정의하면constexpr
지정자는 포인터로 가리키는 타입이 아니라 포인터에 적용한다.
2.5 타입 다루기
2.5.1 타입 별칭
- 타입 별칭 정의하기 -
typedef
1
2
typedef double weges; // weges == double
typedef weges base, *p // base = double, p = double*
- 타입 별칭 정의하기 -
using
1
using SI = Sales_item;
- 이러한 타입 별칭은 타입 이름을 쓸 수 있는 곳 어디든지 쓸 수 있다.
- 포인터,
const
와 타입 별칭- 별칭을 원래 타입으로 바꿔 타입 별칭을 사용하는 선언을 해석하는 것은 올바르지 않을 수 있다.
2.5.2 auto
타입 지정자
auto
타입 지정자를 사용해 컴파일러가 타입을 알려 주도록 할 수 있다.auto
를 타입 지정자로 사용하는 변수에는 반드시 초기값이 있어야 한다.- 복합 타입,
const
와auto
- 참조자를 사용하면 참조자로 참조하는 객체를 실제로 사용한다.
auto
에서는 일반적으로 상위const
절은 무시하지만 하위const
는 유지한다.- 추론한 타입에 상위
const
가 있으려면 명시적으로 지정해야한다.const auto f = ci;
2.5.3 decltype
타입 지정자
1
decltype(f()) sum = x;
decltype
지정자는 피연산자 타입을 반환한다.- 컴파일러는
f
를 호출헀을 때 이 함수에서 반환하게 될 타입을sum
의 타입으로 지정한다. - 상위
const
와 참조자를 포함해 대상 변수의 타입을 반환한다. decltype
과 참조자decltype
에서 하는 추론이 대상 표현식의 형식에 의존한다.
1
2
3
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // int
decltype(*p) c; // 오류, 초기화 하지않음
2.6 데이터 구조 직접 정의하기
- C++에서는 클래스를 정의해 자신만의 데이터 타입을 직접 정의한다.
2.6.1 Sales_data
타입 정의하기
1
2
3
4
5
struct Sales_data {
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
- 위와 같이 기본적으로 클래스를 만든다.
- 클래스는 새 유효범위를 생성해서 다른 곳에 있는 이름을 써도 된다.
- 클래스 데이터 멤버
- 초기화를 할 수 있다.
2.6.2 Sales_data
클래스 사용하기
- 두
Sales_data
객체 더하기 -#include "Sales_data.h"
로 선언하기 - 데이터를 읽어
Sales_data
객체에 넣기 - 두
Sales_data
객체의 합 출력하기
2.6.3 헤더 파일 직접 만들기
- 함수 안에 클래스를 정의하면 기능이 제한되기 때문에 파일 하나에 하나의 클래스를 정의한다.
- 헤더는 한번이상 포함할 수 있으므로 여러 번 포함하더라도 안전하도록 해야한다.
- 전처리기에 대한 간략한 소개
- 전처리기 - 컴파일러를 실행하기 전에 실행해 프로그램 소스 내용을 변경하는 프로그램이다.
- C++ 프로그램에서는 전처리기를 사용해 헤더 보호문을 정의한다. 헤더 보호문은 전처리기 변수에 의존한다.
- 전처리기 변수의 상태는 두가지 중 하나가 될 수있다.
1
2
3
4
5
6
7
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct {
...
}
#endif
This post is licensed under CC BY 4.0 by the author.