LAB/C

[24.08.07] C언어의 기초3

it-lab-0130 2024. 8. 7. 15:14
Chapter 3

1. 이식 가능한 데이터형 : stdint.h 와 inttypes.h

-  int_least8_t : 8비트 부호 있는 정수값을 가질 수 있는 최소폭 데이터를 말함
-  어떤 시스템에서 가장 작은 데이터형이 16비트라면, 그 시스템에서는 int8_t형이 정의되지 않는다. 하지만 int_least8_t형은 사용이 가능하고 16비트 정수로 구현된다.
-  c99와 c11은 가장 빠른 계산을 허용하는 데이터형들의 집합을 정희한다. 
-  예를 들어 사용하는 시스템의 정수형에 대한 별명으로 int_fast8_t형이 정의되어 있을것이다. 이것은 8비트 부호있는 값들을 가장 빠르게 계산할 수 있다.

* intmax_t형 : 부호있는 최대폭 정수형
* uintmax_t형 :부호없는 최대폭 정수형
* longlong 과 unsigned long보다 더 클 수도 있다.

#include <stdio.h>
#include <inttypes.h>
// inttypes.h (헤더파일) : PRId32를, 32비트 부호 있는 값의 적당한 포맷 지정자 (예를들어, d또는 l)를 나타내는 문자열로 정의할 것이다.


// 이식 가능한 데이터형과, 연관된 포맷 지정자의 사용법을 설명하는 예제
int main(void)
{
    int32_t me32;
    // 현재 우리나라는 64비트 컴퓨터지만 전세계적으로 봤을때는 32비트형 컴퓨터도 보편화 되어있다.
    // int32_t :  32비트 부호있는 정수형을 나타낸다. 
    // 사용하는 시스템이 고정폭 데이터형을 지원하지 않는다면 어쩔것인가? C99와 C11은 필요한 대용 이름들에 대한 제2의 이름 집합을 제공한다.
   

    me32 = 45933945;

    printf("먼저, int32_t를 int형이라고 가정한다: ");
    printf("me32 = %d\n",me32);
    printf("이제, 어떠한 가정도 하지말자.\n");
    printf("그 대신에, inttypes.h에 있는 \"macro\"를 사용한다: ");
    printf("me32 = %" PRId32 "\n\n",me32);

    return 0;

}

 

 

 

Chapter 4

2. 문자열 Strlen()함수

" 문자열의 크기를 문자 수로 알아낸다. "

#include <string.h>

- 즉, 문자열 복사, 문자열 검색 등의 함수들과 같은 계열에 속해 있고, string.h헤더파일을 사용한다.

char name[40]

- name의 범위가 [40]이지만 셀값은 문자열 + "Null" 포함한 개수값을 출력한다.

 

#include<stdio.h>
#include <string.h>
// String.h 헤더파일 선언 하면 strlen()을 포함한, 여러 문자열 관련 함수들의 함수 프로토타입이 들어있다.
#define PRAISE "You are an extraordinary being."
int main()
{
    // 사용하는 시스템에 따라 %zd를 인식하지 못한다면
    // %u 또는 %lu를 사용한다.
    char name[40];

    printf("실례하지만 성함이 어떻게 되시는지?\n");
    scanf("%s",name);
    // name 은 문자열이기 때문에 &(앰퍼샌드)가 없어도주소를 찾아줌

    printf("반갑습니다,%s 씨. %s\n",name,PRAISE);
    printf("이름은 %zd글자인데 메모리 셀 %zd개를 차지합니다.\n", strlen(name),sizeof name);\
    printf("감탄문은 %zd글자인데 ",strlen(PRAISE));
    printf("메모리 셀 %zd개를 차지합니다.\n\n", sizeof PRAISE);

    return 0;
}

 

*** PRAISE : 띄어쓰기 포함 셀 개수 출력함

 

3. #define 지시자 /  Const  변경자

float taxrate;
taxrate = 0.015;

- 변수 자료형 선언 => 변수에 상수값 대입 

 

 *** #define 사용

#define TAXRATE 0.015

상수이름 "TAXRATE" 나오고, 그 다음 상수의 값 0.015을 적어준다.

* = (등호) 를 사용하지 않는다.

#define NAME value

1. NAME에 자리에 의미있는 상수이름을 지정해준다.

2. VALUE에 상수값 또는 문자열을 지정하면 된다.

* #define은 문법이 아니고 전처리기가 처리하는 대체 메커니즘이기 때문에 세미콜론(;)을 사용하지 않는다.

 

* 전처리기 란 : main함수 돌기 전 처리 된다는 뜻

더보기

C/C++에서 #이 붙은 요소는 전처리기(preprocessor)라고 불리며, 컴파일을 하기 전에 미리 처리되는 역할을 한다.

 

#define 은 전처리기 중 하나로 만약 선언된 문자가 있다면 해당 문자는 컴파일 시 지정한 문자로 변경됩니다.

3. 변수를 대문자로 표현하는 이유 

- C의 전통이다.

- 프로그램에서 대문자로 표기된 어떤이름을 보게 되었을때, 그것은 변수가 아니고 상수라는 것을 즉시 알게 해준다.

#include <stdio.h>
#define PI 3.14159

int main()
{
    float area, circum, radius;

    printf("피자의 반지름이 얼마냐?\n");
    scanf("%f", &radius);
    area = PI * radius * radius;
    circum = 2.0 * PI * radius;
    printf("피자의 기본 매개변수는 다음과 같다: \n");
    printf("circumference = %1.2f, area = %1.2f\n\n", circum,area);

    return 0;
}

 

* 13번째 줄 

printf("circumference = %1.2f, area = %1.2f\n\n", circum,area);

- %1.2f = %.2f 랑 같은 표현이다. (소수점 아래 2자리까지 출력하라고 지시한다.)

 

 

- #define 지시자는 문자 상수와 문자열 상수에도 사용할 수 있다.

#define BEEP '\a'
#define TEE 'T'
#define ESC '\033'
#define OOPS "야, 드디어 해냈다!"

 

*** 잘못된 예

#define TDES = 20

digits = fingers + TDES;
digits = fingers += 20;

- 이렇게 정의하면, TDES가 20이 아니라 = 20으로 대체된다.

- 3번째 줄 : digits = fingers + TDES ; 

- 4번째 줄 : digits = fingers += 20; 으로 변환된다.

 

Const  변경자

- const 키워드를 사용하여 변수 선언을 상수선언으로 변환하는것

const int MONTHS = 12; // MONTHS는 12를 나타내는 기호상

 

- MONTHS를 읽기 전용 값으로 만든다. (MONTHS의 값은 변경할 수 없다.)

- MONTHS를 표시할 수 있고, 계산에도 사용할 수 있다. 

 

#define / Const  차이점

- 가장큰 차이는 const는 메모리를 할당받고, #define은 메모리를 차지하지 않는다.

(ex. const int 하면 read-only memory에 그 값이 올라가는 것이고 define은 pre-compiling에서 치환된다.

즉, 메모리를 차지하지 않는다.)

ex) Const int a = 125면 Text section 즉 Code memory (Rom 혹은 flash memory)에 들어가게된다.

* Rom / flash memory = 비휘발성 메모리 

* Ram (Data Memory) = 휘발성 메모리 (읽고 쓰기 편집가능)

 

 

위 메모리 구조에서 확인되듯이 const로 선언된 변수는 ROM 영역에 할당되기에 const가 늘어나면 명령어코드가 늘어나며, 자주 호출하게 되면 성능이 저하될 수 있습니다. 말도 안 되게 많이 호출되지 않는 한 성능 저하를 체감할 순 없겠지만 const로 선언된 변수가 자주 호출되고 있다면 const 제거 혹은 다른 대체 방법을 찾아보는 것도 좋을 것 같다.

* #define 단점

const를 사용하면 디버깅 심벌이 생성되기 때문에 디버깅 시 watch window를 이용해서 상수의 값을 확인하기 편하지만 Define을 사용하면 치환이 되기에 디버깅 하기 불편한 부분이 있다.

*** #define 사용할때 

- 매크로 함수로 많이 사용된다.

* 매크로 함수 : C언어에서는 #define 선행처리 지시문에 인수로 함수의 정의를 전달함으로써, 함수처럼 동작하는 매크로를 만들 수 있습니다. 이러한 매크로를 함수 같은 매크로(function-like macro) 또는 매크로 함수라고 합니다.

#include <stdio.h>

#define SUB(X,Y) X-Y

#define PRT(X) printf("계산 결과는 %d입니다.\n", X)  

 

int main(void)

{

    int result;

    int num_01 = 15, num_02 = 7;  

 

    result = SUB(num_01, num_02);

    PRT(result);

    return 0;

}

 

 

참고 : https://www.tcpschool.com/c/c_prepro_macroFunc

4. 명단 상수의 사용

Limits.h (헤더파일) / float.h (헤더파일)

- 정수형 과 부동소수점형의 크기 제한에 관련된 자세한 정보를 각각 제공한다.

* Limits.h

 #define INT_MAX +32767

 #define INT_MIN -32768

- 이 상수들은 int형이 가질 수 있는 최대값과 최소값을 나타낸다.

- 32비트 int형을 사용한다면, 이 기호 상수(#define INT_MAX)들이 다른 값으로 정의 되어 있을것이다.

- 사용자 시스템이 4바이트 int형을 사용한다면, Limist.h파일에는 4바이트 int형에 적합한 INT_MAX와 INT_MIN이 정의 되어 있을것이다.

- printf("이 시스템에서 int형의 최대값 = %d\n", INT_MAX); 코드를 사용하여 출력할 수 있다.

 

* float.h

- float형과 double형이 지원하는 유효숫자의 자릿수를 나타내는 FLT_DIG, DBL_DIG와 같은 상수를 정의 하고 있다.

- double형과 long double형의 경우에, 이름에서 FLT가 DBL과 LDBL로 각각 대체되어 있다.

***C99 표준을 완전하게 지원하지 않기 때문에 LLONG_MIN 식별자를 인식 못할 수도 있다.

// defines.c   : limits.h와 float.h에 정의되어 있는 기호 상수들을 사용한다.

#include <stdio.h>
#include <limits.h>
#include <float.h>

int main()
{
    printf("이 시스템이 표현하는 수의 한계: \n");
    printf("int형 최대값: %d\n", INT_MAX);
    printf("long long형 최소값 : %lld\n",LLONG_MIN);
    printf("이 시스템에서 1바이트는 %d이다.\n",CHAR_BIT);
    printf("double형 최대값 : %e\n",DBL_MAX);
    printf("float형 최소값 : %e\n",FLT_MIN);
    printf("float형 정밀도는 소수점 아래 %d자리 까지 \n",FLT_DIG);
    printf("float형 epsilon = %e\n\n", FLT_EPSILON);

    return 0;
}

** Epsilon :다른 말로는 1보다 큰 가장 작은 숫자를 머신 입실론이라 한다.

FLT_EPSILONfloat.h 헤더 파일에 정의되어 있으며 이 값을 머신 엡실론(machine epsilon)이라 부릅니다. 어떤 실수를 가장 가까운 부동소수점 실수로 반올림하였을 때 상대 오차는 항상 머신 엡실론 이하입니다. 즉, 머신 엡실론은 반올림 오차의 상한값이며 연산한 값과 비교할 값의 차이가 머신 엡실론보다 작거나 같다면 두 실수는 같은 값이라 할 수 있습니다. 만약 double, long double을 사용한다면 머신 엡실론은 DBL_EPSILON, LDBL_EPSILON을 사용합니다.

 

** 실행결과

숫자 범위에 E라고 쓴부분 : 이 표현방법은 지수를 표현하기 위한 방법

E이후 나오는 숫자는 10의 거듭제곱을 나타내는 숫자이다.

123 = 1.23 E2

0.12 = 1.2 E-1

 

즉 정수 부분을 항상 한자리로 만들고 나머지 소수부분은 10의 거듭제곱으로 표현하는 거죠.

참고로 printf 함수의 %E 는 이런 지수 표현 방법으로 화면에 출력한다는 의미입니다.

 

두 변수의 차이는 소수의 정밀도 차이가 있습니다.

여기서 정밀도라는 것은 소수점 이하 몇자리까지 표시하는가를 나타냅니다.

각 변수의 정밀도는 다음과 같습니다.

float - 7자리

double - 14자리