ComputerScience/C, C++

C, C++ namespace, 메인함수 원리, 유효정밀도, Shift(쉬프트)연산자, 연산자우선순위, 난수발생 등

Moai27 2018. 7. 2. 22:41


소개

18년 07월 02일 월요일, 여름방학인 오늘부터  C / C++ 에대한 전반적인 공부를 시작!!

전공은 Computer Science이며, 프로그래밍 공부가 많이 부족한 상태다!!

게임 프로그래머가 되고 싶어, 시작한 공부인 만큼 기초를 잘 다져서 꼭 이루어내겠다.


블로그를 시작한 이유?..

 전체적으로 훑어 본 적은 있으나 체계적으로 정리하지 못했던 문법들을 정리해보기에 좋아보였기 때문.


날 밝을때는 강의등을 통한 학습 -> 

날 어두울 때는 예제들을 통한 복습 ->

개념정리를 블로그에 날마다 할 계획.

(목요일은 쉴예정)


전반적으로 구글링, 유투브 (특정채널), 가지고있는 책을 위주로 참고해서 정리 할 예정. 


1. namespace (네임스페이스)

  • 개념 : 여러 가지 식별자들을 이름이 있는 범위로 그룹화하는 기법

 - 식별자들의 종류 : 변수, 함수, 구조체, 클래스, 공용체, typedef 등

  • 동일한 이름을 갖는 함수나 변수라도 서로 다른 namespace 안에 만들 수 있다.
  • 코드 내에서 이름이 같은 식별자나 라이브러리 사용하는 과정에서 생기는 식별자명 충돌 (name clash) 문제를 해결할 수 있음.
  • scope resolution operator ('::')를 사용하여 네임스페이스를 구분함. 

ex) 네이스페이스명 :: 식별자명

  • using 지시자 :  네임스페이스내의 식별자를 네임스페이스명 없이 사용하기위한 명령어.
  1. using 네임스페이스명 :: 식별자명;       // 네임스페이스 내의 하나의 식별자명만 using 하기
  2. using namespace 네임스페이스명;       // 네임스페이스 내의 모든 식별자를 바로 사용 하기


2. main()

  • main함수 없으면 링크에러가 발생한다. 
  •  동작순서 : main()가 어디에 위치에있던간에 startup code가 찾아서 main()을 불러준다.  그리고 main함수 안의 내용들을 처리하고 마지막 return 값을 startup code가 받아준다. 리턴값에 대한 의미는 UNIX, LINUX와 같은 운영체제에서는 정상종료와 비정상종료를 나누는 것과 같이 의미있게 다루지만, Windows같은경우는 main()의 리턴값을 특별한 의미로 다루지 않는다.
  • 여기서 Startup Code가 하는 일은
  1. 메모리를 확보(Ram안에)
  2. (buffer할당)
  3. main함수 호출
  4. main함수의 리턴값을 OS에 전달
  • 메인함수는 함수의 정의부만 보이는 사용자 정의함수이다.  우리가 부르는게 아니기 때문이다.
cf.) printf와 같은 함수들의 정의부는 어디에있을까? -> 라이브러리루틴에 있다.


3. % ? . ?
  • % 필드너비지정 . 정밀도
  • 필드너비지정은 출력될 데이터가 크기에 맞지 않으면 크기 무시
  • 정밀도는 %f, %e, %g에서는 소수이하 자리수를 의미
  • 정밀도는 %s에서는 프린트될 최대 문자의 개수를 의미
  • 정밀도는 %d.에서는 출력될 수의 최소개수를 의미
  • %*.* 필드의 너비나 정밀도등을 임의로 지정하고자 할 때 사용

  ex) int b=10;

 int c=3; 

 double fa = 123.7546;

printf("%*.*lf\n", b, c, fa); -> %10.3lf 의 형태로 인식 

(10자리폭(소수점포함)에 소수점은 3자리) 

결과-> 빈빈빈123.755



4. 유효정밀도

  • 개념 : 실수 데이터형에만 있는개념으로 유효숫자를 몇 자리까지 저장할 수 있는가를 10진수 기준으로 나타낸것.
  • float 형 : 7 ~ 8자리 , double 형 : 14 ~ 16자리

 cf) 실수형의 오차 2가지

  1.  유효정밀도에 의한 오차
  2. 2진수 변환 시 순환소수로 변환되어 발생하는 오차 

   ex.) float fa = 7.33f;



5. const , #define, enum 의 비교

  • #define(매크로 정의)는 프로그램을 읽기쉽게하고, 유지보수를 용이하게 해주며, 변수 사용 시 보다 처리속도를 높여준다. but 실행파일의 크기는 커질수 있다.
  • #define을 쓴 매크로 함수는 타입에서는 자유로운편이지만 정밀도는 떨어질 수 있다. 하지만 타입에 민감한 경우는 조심해야 한다.  

    ex) #define mod(a,b)  a%b  -> 이 경우 double형이 날라오면 바보가 된다.

  • const 변수는 반드시 선언문에서만 초기화가 가능하다. 초기화 이후 실행문에서는 그 값을 변경할 수 없다.
  • 포인터에 const를 사용할 경우 포인터의 대상이 상수화되는 경우와 포인터 변수 자체가 상수화 되는 경우가 있다.

=> const가 변수의 이름과 가깝냐 머냐를 보면 된다.
  1.  포인터의 대상이 const화 되는 경우

const int *p;    // 상수화된 int를 가리키는 *p의 운명!!

int abc = 7;

p = &abc;

*p -= 10;     ( X )

abc -=10;    ( O )


  B. 포인터 변수가 const화 되는 경우


int abc[3] = {10, 20, 30};

int * const p = abc;

printf("%d \n", *p);         ( O )

printf("%d \n", ++*p);     ( O )    // 포인터가 가리키는곳을 증가시키는 것이니 괜찮다!

printf("%d \n", *++p);     ( X )    // 포인터를 증가시키는 경우가 되버린다.


  • 따라서 const char * cp = "kiwi";   <--- 이런표현을 쓰는게 좋은 것이다. ( string 영역은 Read Only 영역이기에 )
  • enum(나열형)을 이용하면 정수상수를 기호 이름으로 선언해서 사용하거나 정수기호상수를 저장하는 변수를 선언하여 사용할 수 있다.
  • enum은 이름을 부여할 수 있기에 결과적으로 가독성을 높여준다. -> Switch문과 잘 어울림

6. Shift 연산자
 - 비트단 좌/우 이동 연산자

Shift 방향 및 대상체 부호

공백 메우기 

 << (Left Shift)

 signed

0으로 채움 

unsigned 

 >> (Right Shift)

 signed

 sign bit값으로 채움

 unsigned

0으로 채움 


  • 왼쪽 쉬프트 하나당 * 2(곱하기2) 한 효과를 낼 수 있기 때문에 연산속도가 빠르지만 그 효과가 영원하지는 않다는 것에 주의 해야한다.
  • 유효숫자가 Sign Bit로 가면 음수로 되기도하고 거기서 또 쉬프트하면 유효숫자가 빠져나가버리기도 한다...
  • 마찬가지로 오른쪽 쉬프트 하나당 / 2(나누기2)한 효과를 낼 수 있지만 이 또한 주의할 것!

ex )  shift 연산자를 이용해 특정정수(n)의 값의 12배를 구하고자 한다면???

-> n의 8배수 + n의 4배수 형태로 결과를 얻으면 된다.

-> 즉, (n<<3) + (n<<2)로 계산한다.



7. 연산자 우선순위표 (C언어기준)


 순위 

명칭 

연산자 

결합방향 

1

1차 연산자 

() [] . -> 

->

2

다항 연산자

+ - ! ~ (type) sizeof ++ -- & *

<- 

3

승법 연산자

* / % 

-> 

4

가법 연산자 

+ - 

5

Shift 연산자 

<<  >> 

6

관계 연산자 

<  >  <=  >= 

7

등가 연산자 

==  != 

8

bit 곱 연산자 

 9 

bit 차 연산자 

 10 

bit 합 연산자 

 11 

논리곱 연산자 

&& 

 12 

논리합 연산자 

|| 

 13 

조건 연산자 

? : (삼항연산자) 

 ->

 14 

대입 연산자 

=  +=  -=  *=  /=  %=  <<=  >>=  &=  |=  ^= 

 <-

15

순차 연산자 

 ->


* 순위 3~12는 이항연산자.



8. 난수발생 방법

  • #include <time.h>

    srand((unsigned int)time(0));                      // 현재시간 기준으로 시간값 뽑아올수있다.
    cout << rand() % 100 << endl;                 // 0~99 
    cout << rand() % 101 + 100 << endl;        // 100~200
    cout << (rand() % 10000 / 100.f) << endl;  // 0~99.99%  \
-> rand % 10000 이 한번에 뽑을수 있는 최대의 수... 만자리... 응용해서 써야 더 큰 수 조절가능