본문 바로가기
1.B. Low Level Engineering/Micro Controller Unit

[MCU] T1.1 (정수) 데이터란 Intro. to Datum

by Never Settle Down 2023. 2. 3.
반응형

 

내가 좋아하는 켈리 클락슨

서두르지 말고 천천히 천천히 시작하자고 넣었다.

 

 

 

이번 챕터는 바로 안 보고 제껴도 된다.

당장 현실성 없는 이야기만 지껄이고 있고,

'그래서 이걸 어따 씀?'이란 생각이 먼저 들 수도 있기 때문.

 

나중에 필요할 때 돌아와서 확인하면 된다.

그때그때 링크 걸어줄게 Marius.

 

 

 

 

하염없이 LED만 껌뻑거리는 아두이노를

연산장치로 써보자.

 

 

통신은 시리얼 통신으로 할 것이다.

4편 시리얼 콤을 참고하면 디테일을 볼 수 있다.

https://thewanderer.tistory.com/36

 

 

 

 

 

기본적으로

아두이노는  C++ 언어를 쓴다.

C가 아냐.

 

둘이 무슨 차이냐고?

나도 몰라. ㅋ.

C++은 "객체지향" 언어, Object Oriented Programming Language인데

Java처럼 찐객체는 아니고

어셈블리어보다 좀 나은 C언어, 코딩하는 사람보다 하드웨어에 더 친화적인 언어에

기능을 쫌 얹기위해 노력했다. 정도.

 

 

그럼 객체는 무엇이냐.

그건 나중에.ㅋㅋㅋ

아두이노에서 객체 개념을 써본 적은 없으니까. 나중에 필요하면 여기에 추가하것음.

 

 

 

 

- 기본 단위 데이터 (Unit Data)

이건 내가 이름 붙인거라 어디 검색해도 안 나올듯.

 

정수와 실수.

1과 1.00000000...

 

 

정수를 표현하는법:

- int

- int의 변종들

 

실수를 표현하는법: (2.2 편 참조)

- Double

- Float

- Sorry my mistake

 

 

정수

int:

인티져, integer.

https://cdn.arduino.cc/reference/en/language/variables/data-types/int/

 

Arduino Reference

Example Code This code creates an integer called 'countUp', which is initially set as the number 0 (zero). The variable goes up by 1 (one) each loop, being displayed on the serial monitor. int countUp = 0; //creates a variable integer called 'countUp' void

cdn.arduino.cc

글로 구구절절 쓰니 안 읽힌다.

사진 두 장 때려박을테니 참고하세요.

 

 

 

 

아두이노에서 int는 16비트로 구성되어있다.

 

0000 0000 0000 0000 = 0

이런 식으로.

 

값의 범위:

[ ( (2^16) / 2 ) ]  ~ [ ( (2^16) / 2 ) - 1 ]

 

여기서 마이너스가 보이지?

음수를 표현할 수 있다.

 

맨 앞자리비트 (MSB? 이건 확인하고 적어드림)가

- 0이면 양수

- 1이면 음수

로 표현한다.

 

그래서 -값의 끝자리 절대값은 +값의 끝자리 절대값보다 1이 더 커.

좌우 반띵했는데, 양의 자리 첫 번째 숫자를 0으로 양보해야되거든.

 

 

Unsigned Int

만약에 나는 음수를 쓸 일이 없어.

그래서 16비트를 0 ~ 66,535까지 쓰고싶다.

(예를 들어, 죽빵을 날리고 횟수를 카운트를 할 때 -1번째, -2번째... 같은 숫자는 없으니까)

그러면 unsigned 를 붙이면 됩니다.

 

unsigned int 값의 범위:

0 ~ 66,535

(2^16 - 1)

 

 

Byte < Short = int < Long < Long Long

아두이노는 8비트 프로세서를 탑재했어.

이 말은, 한 번에 8비트씩 묶어서 계산할 수 있다는 말임.

 

16비트 int 를 8비트 프로세서로 연산하려면?

반띵해서 두 번 연산.

 

 

 

나는 죽빵을 200번 이상 날릴 일이 없다고 치자.

그럼 굳이 16비트의 큰 데이터를 쓸 일이 있을까?

 

Byte

그럴때 쓰는게 Byte.

8비트, Byte는 unsigned 무조건

0 ~ 255 의 값만 표현할 수 있다.

 

스타크래프트 1에서 유닛 킬 수가 255를 못 넘기는거 아려나?

(마린이나 드랍십 파일럿은 스타 하도 많이해서 알 듯)

그게 Byte로 저장해서 그려.

 

 

Short.

16비트의 정수를 나타낼 때 쓴다.

short: -32,768 ~ 32,767

unsigned short: 0 ~ 65,535

 

...?

그럼 short랑 int랑 똑같은데 왜 이름이 달러?

 

대부분의 오~래된 PC는 32비트 프로세서를 탑재하고 있어서

int의 길이가 32비트야.

 

이런 PC에서 C코딩을 하면 short가 int의 반쪽짜리 데이터가 되는데

아두이노는 후져서 원래 16비트 데이터를 int로 쓸 뿐,

 

int를 쓰면 "너가 쓰는 기본 길이의 정수를 쓰셈" 이고

short를 쓰면 "너 16비트로 고정" 이라고 지칭하는 정도가 된다.

 

그냥 그런가보다~ 하면 된다.

 

 

Long

죽빵을 unsigned int로 육만 오천번정도 때릴 수 있는데,

나는 십만번을 때리고 싶어.

 

16비트를 2배 뻥튀기해서 32비트로 저장하자

그게 long

 

long int:

-2,147,483,648 ~ 2,147,483,647

unsigned long int:

0 ~ 429,496,735

 

언사인드 인트를 쓰면

무려 4.29억번을 때릴 수 있다.

 

 

물론 큰 숫자를 저장할 수 있어서 좋다만,

- 연산을 4번 해야한다는 점 (8비트 프로세서이므로)

- 메모리를 일반 int에 비해 2배를 잡아먹는 점

등으로 진짜 큰 수 아니면 잘 안써.

 

Long Long

long으로도 부족하다.

32비트 데이터도 부족하다.

 

64비트로 저장해버리면 된다.

이름은 long long.

 

unsigned long long int_64bit;

나였으면 unsigned extra long ~~~;

이렇게 했을 것 같은데.

(아님 뻑킹 롱 ㅋㅋ)

 

unsigned 기준

0 ~ 2^64

까지 표현 할 수 있다.

 

long long은 센서에서 요구하는정도가 아니면

잘 쓸 일이 없긴 하다.

 

알아두면 좋다.

 

 

 

 

예제를 함 보까.

Integer Range Test.ino
0.00MB

byte flag=0;

byte int_byte = 0;            // flag = 0
short int_short = 32766;          // flag = 1
int int_int = 32766;              // flag = 2
long int_long = 2147483600;            // flag = 3
long long int_longlong = 9223372036854775000;   // flag = 4

unsigned short usign_int_short = 0; // flag = 5
unsigned int usign_int_int = 0;     // flag = 6 
unsigned long usign_int_long = 4294967290;   // flag = 7
unsigned long long usign_int_longlong = 18446744073709550000;// flag = 8

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Begining...");
}

void loop() 
{
  switch(flag)
  {
    case 0: //unsigned byte, 8 bit
      if(hasOverflowedYet(int_byte++)) {
        Serial.print("byte range: ");
        Serial.print(int_byte);
        Serial.print(" ~ ");
        Serial.println( (byte)(int_byte-1) );
        flag++;
      }
    break;

    case 1: //signed short int , 16bit
      //Serial.println(int_short);
      if(hasOverflowedYet(int_short++)) {
        Serial.print("signed short int range: ");
        Serial.print(int_short-1); //already overflowed. from positive to negative
        Serial.print(" ~ +");
        Serial.println( (short)(int_short-2) );//re overflow
        flag++;
      }
    break;

    case 2: //signed int , 16bit
      if(hasOverflowedYet(int_int++)) {
        Serial.print("signed int range: ");
        Serial.print(int_int - 1);
        Serial.print(" ~ +");
        Serial.println( (short)(int_int - 2) );
        flag++;
      }
    break;

    case 3: //signed long int , 32bit
      if(hasOverflowedYet(int_long++)) {
        Serial.print("signed long int range: ");
        Serial.print(int_long - 1);
        Serial.print(" ~ +");
        Serial.println( (long)(int_long - 2) );
        flag++;
      }
    break;

    case 4: //signed long long int , 64bit
      if(hasOverflowedYet(int_longlong++)) {
        Serial.print("signed long long int range: ");
        print_ll(int_longlong - 1);
        Serial.print(" ~ +");
        print_ll( (long long)(int_longlong - 2) );
        Serial.println();
        flag++;
      }
    break;

    case 5: //unsigned short int , 16nit
      if(hasOverflowedYet(usign_int_short++)) {
        Serial.print("unsigned short int range: ");
        Serial.print(usign_int_short);
        Serial.print(" ~ ");
        Serial.println( (unsigned short int)(usign_int_short - 1) );
        flag++;
      }
    break;

    case 6: //unsigned int , 16bit
      if(hasOverflowedYet(usign_int_int++)) {
        Serial.print("unsigned int range: ");
        Serial.print(usign_int_int);
        Serial.print(" ~ ");
        Serial.println( (unsigned int)(usign_int_int - 1) );
        flag++;
      }
    break;

    case 7: //unsigned long int , 32bit
      if(hasOverflowedYet(usign_int_long++)) {
        Serial.print("unsigned long int range: ");
        Serial.print(usign_int_long);
        Serial.print(" ~ ");
        Serial.println( (unsigned long int)(usign_int_long - 1) );
        flag++;
      }
    break;

    case 8: //unsigned long long int , 64bit
      if(hasOverflowedYet(usign_int_longlong++)) {
        Serial.print("unsigned long long int range: ");
        //Serial.print("%llu", usign_int_longlong);
        print_ll(usign_int_longlong);
        Serial.print(" ~ ");
        //Serial.println("%llu", (unsigned long long int)(usign_int_longlong - 1) );
        print_ll( (unsigned long long int)(usign_int_longlong - 1) );
        flag++;
      }
    break;

    case 9:
      Serial.println("\nDone. Peace out.");
      Serial.end();
    break;

    default://sleep
      delay(1000);
  }
}

bool hasOverflowedYet(byte datum)                   { return ( (byte)(datum + 1) < datum); }
bool hasOverflowedYet(short datum)                  { return ( datum < 0 ); }
bool hasOverflowedYet(int datum)                    { return ( datum < 0 ); }
bool hasOverflowedYet(long datum)               { return ( datum < 0 ); }
bool hasOverflowedYet(long long datum)          { return ( datum < 0 ); }
bool hasOverflowedYet(unsigned short datum)     { return ( (unsigned short)(datum + 1) < datum); }
bool hasOverflowedYet(unsigned int datum)           { return ( (unsigned int)(datum + 1) < datum); }
bool hasOverflowedYet(unsigned long datum)      { return ( (unsigned long)(datum + 1) < datum); }
bool hasOverflowedYet(unsigned long long datum) { return ( (unsigned long long)(datum + 1) < datum); }

void print_ll(unsigned long long val) {
    if (val < 10) Serial.print((unsigned int) val);
    else {
        print_ll(val / 10);
        Serial.print((int)(val % 10));
    }
}
void print_ll(long long val) {
    int sign = 1;
    if (val < 0) { Serial.print("-"); sign = -1; }
    print_ll( (unsigned long long)(val * sign) );
}

롱롱 프린트가 안되서 싸제 프린터를 만드느라 좀 했다. 오버플로 생긴걸 지가 알아서 보정해버려서 더 고생을 좀 했다. '?? 왜 안되지??' &nbsp; ㅋㅋㅋ;

(일일이 캐스팅해주고, signed는 저 오버플로 감지 (datum+1 < datum)가 안 먹혀서 결국 0이랑 비교했다)

(signed int의 경우 MSB를 1과 and 연산시키려다가, < 0 이 보기 더 좋을 것 같아서 다시 고쳤다 ㅋㅋ)

(사용자 정의 함수의 경우, 인풋 타입과 내용은 다르지만 함수명은 같게 할 수 있다는 것을 보여주기 위해 저렇게 했다)

(16비트 이상의 숫자는 연산이 너~무 오래걸려서 초기값, init을 Range에 근접하게 주었다)

 

 

각 타입별로 1씩 더했다.

막무가내로 막 더했다.

 

 

그러면, 아까 위에서 언급한 숫자의 범위 (e.g. 바이트 = 0 ~ 255) 를 넘으면 어떻게되나요?

 

Unsigned의 경우: 0으로 초기화된다

Signed의 경우: -쪽 제일 낮은 값으로 바뀐다.

 

 

엄밀히 말하자면

"오버플로우"가 생긴 것이다.

넘쳐서 흐른다, 오버 플로우.

 

 

이런 메모리 오버플로로 서버를 공격해서

정보를 탈취한다든지 시스템을 고장낸다든지 할 수 있다.

 

 

아두이노 레벨에서는 단순히 값이 초기화되고 만다.

이를 역이용해서 자동 초기화를 시켜줄 수도 있다.

 

 

 

 

Marius, 이해 되나???

너무 상위레벨 코드를 막 던져버린건가.

 

트레일 블레이저 뽑았던 형님이면 알아들을텐데.

아, 애초에 그정도면 데이터타입 설명할 필요가 없겠구나.

 

 

궁금한거 있으면 톡 때리셈.

 

 

 

아휴. 실수랑 구조체도 해야되는데

너무 길어진다.

 

포스팅을 쪼개야겠다.

 

 

 

 

 

끝. End of Document

반응형

댓글