Brise

[C++ 기본] 4. Variable 본문

프로그램/C,C++

[C++ 기본] 4. Variable

naudhizb 2022. 1. 14. 23:39
반응형
// 4_변수1
#include <iostream>

// C++ 은 C언어의 변수 관련 문법을 더욱 발전시켰습니다.

struct Point 
{
    int x, y; 
};

int main()
{
    int n1 = 0b1; // 2진수 표기법, C++11 부터 지원
    int n2 = 1'000'000; // digit separator, C++11부터
                    // 원리 : 정수형 리터럴 사이의 ' 는
                    //      컴파일러가 무시

    struct Point p1; // C언어 스타일
    Point p2; // C++언어 스타일.

    //foo()
    int n3; // 함수 중간에 변수 선언. 
            // C89 : error
            // C99 : ok. 
            // C++ : ok.

}

C와 C++ 문법 기준이 개선되며 변수 선언 위치 및 방법이 크게 개선되었습니다.
컴파일러의 버전에 따라 선언위치, prefix, 리터럴 값의 가독성 증가를 위한 divider등을 추가할 수 있습니다.
또한 C언어에서 불필요하게 typedef struct ... {} ...와 같은 패턴을 사용하지 않아도 되도록 C++언어에서는 구조체 타입을 좀 더 편리하게 사용할 수 있도록 하였습니다.

// 4_변수1
#include <iostream>

struct Point
{
    int x, y;
};
int main()
{
    // 20page - 중요한 변화.!
    //int n = 10;
    //int x[3] = { 1,2,3 };
    //Point p1 = { 1,2 };

    // 일관된 초기화(uniform initialization) 문법 - C++11
    // 모든 종류의 변수를 초기화 할때 {} 사용
    // int n = { 10 };
    // int x[3] = { 1,2,3 };
    // Point p1 = { 1,2 };

    int n { 10 };
    int x[3] { 1,2,3 };
    Point p1 { 1,2 };

    // 직접 초기화(direct initialization) : =이 없는것
    // 복사 초기화(copy   initialization) : =이 있는것

    // {} 로 초기화(직접 또는 복사)시 데이타 손실 발생하면 error.
    int n2 = 3.4;   // ok.. 하지만 나쁜 코드,
    int n3 = { 3.4 }; // error. preventing narrow 라는 문법
    
    char c = { 300 }; // error
}

C언어에서는 primitive type에 대한 값을 선언할 때 {}를 사용할 수 없었던 것과 달리 모든 변수선언에 대하여 {}를 사용할 수 있습니다.
하지만 이 경우 좀더 strict한 기준을 사용하게 되어 데이터 타입 변형을 통한 손실이 있을 경우 컴파일러 오류를 발생시킵니다. 이 때문에 런타임 이전에 발생할 수 있는 Human-error를 미리 확인할 수 있습니다.

#include <iostream>
struct Point
{
    int x, y;
};
void foo(int n)    {} // int n = {3}
void goo(Point pt) {}

int main()
{
    foo(3);
    foo({ 3 }); // int n  = {3}

    Point p = { 1,2 };
    goo(p);
    goo({ 1,2 }); // ok.. Point pt = {1,2}
}

C언어에서는 primitive type에 대해서만 리터럴을 선언할 수 있었지만(무명 변수)
C++언어에서는 구조체에 대해서도 리터럴을 선언할 수 있습니다.

int main()
{
    int x[3] = { 1,2,3 };
    //int n = x[0];
    auto n = x[0]; // 우변의 표현식을 가지고 좌변의 타입 결정
                    // 컴파일러가 결정. 실행시 성능저하 없습니다.
                    // C++11
    decltype(n) n2; // () 안의 표현식과 동일한 타입
                    // C++11
    auto a1 = x; // a1의 타입은 ?  
                // 1. int a1[3]    2. int*
                // int a1[3] = x;  // error
                // int* a1 = x;    // ok
    decltype(x) d1; // int d1[3]
    decltype(x) d2  = x; // int d1[3] = x 이므로 error
    // 22 page 제일 아래 
    //decltype(x[0]) d3; // error.  d3 int&
}

auto와 decltype을 이용하여 좀 더 유연한 프로그래밍이 가능합니다. 또한 이 부분의 경우 컴파일 타임에 결졍되므로 실행 성능에는 문제가 없습니다만, 개발자가 해당 내용에 대하여 잘 파악하고 있지 않은 경우 오류가 발생할 가능성이 높습니다.
C++의 경우 &에 대하여 주소와 레퍼런스 2개의 값을 모두 사용할 수 있어 이 부분에 대한 주의가 필요합니다.

// typedef int DWORD;
// typedef void(*PF)();

// typedef : 타입에 대한 별칭(alias) 만들기
// using   : 타입에 대한 별칭 + 템플릿 별칭 만들기
//            

// C++11 using 
using DWORD = int;
using PF = void(*)();

int main()
{
    DWORD n;  // int
    PF    f;  // 함수 포인터
}

C에서 typedef를 이용한 것과 마찬가지로 C++에서는 using 키워드를 이용하여 변수 타입에 대한 별칭을 만들 수 있습니다. 추가로 template에 대한 별칭 또한 만들 수 있습니다.

// 4_변수6.cpp   25 page 
struct Point
{
    int x, y;
};
int main()
{
    Point pt = { 1,2 };

    int x = pt.x;
    int y = pt.y;

    // C++17. structure binding
    // VC++ 2017, 2019 : 디폴트로 C++14까지 지원
    //                /std:c++17 또는 /std:c++latest

    // g++ 8.x, 9.x : 디폴트로 C++14까지 지원
    //                -std=c++17

    auto[a, b] = pt; // 반드시 auto 만 가능

    int arr[3] = { 1,2,3 };

    auto[a1, a2, a3] = arr;  // ok

    // 64 bit 타입
    long long n3; // 64 bit 정수.
}

최근 C++ 문법의 경우 C언어에서는 지원되지 않은 구조체를 이용한 개별 변수의 초기화 기능(structure binding)을 지원합니다.
다만, 이 경우 auto의 선언이 강제됩니다.

반응형
Comments