본문 바로가기
IVS/C 프로그래밍

[C] 형변환, 비트연산자

by 코곰_ 2025. 1. 13.

- mcu는 c에 최적화되어 있다. (안전등급 충족 X)

 

조건문

- if문에서 왼쪽 식이 만족하지 않으므로, y++은 실행되지 않는다.

#include <stdio.h>
int main() {
    int x = 5; int y = 10;
    if (x < 0 && y++  == 15){
    printf("이 코드는 실행되지 않습니다.\n");
    }
    printf("y = %d\n", y); // y = 10
}

 

 

형변환

#include <stdio.h> 
#include <stdlib.h>
int main() {
    // %u: unsigned_int
    char s8_1 = 0, s8_2 = 0;
    short s16_1 = 32767;
    int s32_1 = -1;
    unsigned int u32_1 = 1u;
    printf("1. %d\n", sizeof(s8_1 + s8_2));
    printf("2. %d, %d, %u\n", sizeof(32767 * 100000), 32767 * 100000, 32767 * 100000); 
    printf("3. %d, %u\n", -1, -1);
    if (s32_1 < u32_1) { // unsigned로 형변환 된다. 
        printf("4. s32_1 < u32_1 is true\n");
    }
    else {
        printf("4. s32_1 < u32_1 is false\n");
    }
    system("pause");
    return 0;
}

 

* 자료형 처리 속도: char < int < long < float < double 

* 명시적 형변환을 권장함.

원하는 자료형이 char 타입보다 크기가 작아서 

 

 

 

 

 

 

 

 

shift 연산

(연습1)

1. SWE_EN = Enable

2. BR_RATIO = Ratio <= 4

3. BR = 500kbp/s

위와 같이 registerValue 값을 바꿔보자. 

#include <stdio.h> 
#include <stdlib.h>
int main()
{
    unsigned char registerValue = 0;
    registerValue |= (1<<7); 
    
    registerValue |= (1<<2);
    for (int i = 7; i >= 0; i--) {
        printf("%d", (registerValue & (1 << i)) ? 1 : 0);
    } 
    printf("\n"); // 10000100
    return 0;
}

 

 

 

 

(연습2)

#include <stdio.h> 
#include <stdlib.h>
#include <stdint.h>
int main()
{
    uint8_t flags = 0;
    // 0 번째 Bit 부터 Fail_0 ~ 7 이다.
    // 0,2,3,5,7 번째 Fail 이 발생했을 때 이를 입력하라
    flags |= (1 << 0); // Fail_0
    flags |= (1 << 2); // Fail_2
    flags |= (1 << 3); // Fail_3
    flags |= (1 << 5); // Fail_5
    flags |= (1 << 7); // Fail_7

    // Fail_0부터 Fail_7까지 값을 검색하고 출력합니다.
    for (int i = 0; i < 8; i++) {
        uint8_t flag = (flags & (1 << i)) ? 1 : 0;
        printf("Fail_%d: %d\n", i, flag);
    }
}

 

 

 

 

 

 

 

 

(연습3)

각 Can Bit별 Parsing하는 code를 작성하라

#include <stdio.h> 
#include <stdint.h>

int main() {
    //Current Data : 164,32,0,4  G Sensor : 32,38,4,a
    uint8_t canDataArray[8] = { 0x64, 0xC9, 0x00, 0x00, 0x01, 0x32, 0x4E, 0x28 }; 
    
    // 10비트 단위로 추출된 데이터
    uint16_t currentData1, currentData2, currentData3, currentData4;
    currentData1 = (canDataArray[0]) | (((uint16_t)canDataArray[1] & 0x03) << 8);
    currentData2 = (canDataArray[1] >> 2) | (((uint16_t)canDataArray[2] & 0x0F) << 6);
    currentData3 = (canDataArray[2] >> 4) | (((uint16_t)canDataArray[3] & 0x3F) << 4);
    currentData4 = (canDataArray[3] >> 6) | (((uint16_t)canDataArray[4] << 2));

	// 6비트 단위로 추출된 데이터 
    uint8_t gsensor1, gsensor2, gsensor3, gsensor4;
    gsensor1 = canDataArray[5] & 0x3F;
    gsensor2 = (canDataArray[5] >> 6) | ((canDataArray[6] & 0x0F) << 2);
    gsensor3 = (canDataArray[6] >> 4) | ((canDataArray[6] & 0x03) << 4);
    gsensor4 = (canDataArray[7] >> 2);
    printf("Current Data:\n"); 
    printf("Current 1: %x\n", currentData1); 
    printf("Current 2: %x\n", currentData2); 
    printf("Current 3: %x\n", currentData3); 
    printf("Current 4: %x\n", currentData4);
    printf("\nGsensor Data:\n"); 
    printf("Gsensor 1: %x\n", gsensor1); 
    printf("Gsensor 2: %x\n", gsensor2); 
    printf("Gsensor 3: %x\n", gsensor3); 
    printf("Gsensor 4: %x\n", gsensor4);
    return 0;
}

 

  • OR 연산(|)은 같은 위치의 비트 중 하나라도 1이면 1을 반환
  • AND 연산(&)은 같은 위치의 비트가 모두 1일때만 1 반환

 

  • 0x03의 2진수 표현은 0000 0011 -> and 연산하여, 하위 2비트를 추출
  • 0x0F의 2진수 표현은 0000 1111 -> and 연산하여, 하위 4비트를 추출
  • 0x3F의 2진수 표현은 0011 1111 -> and 연산하여, 하위 6비트를 추출

 

 

 

 

 

Little Endian, Big Endian

: 데이터를 메모리에 저장하거나 전송할 때 바이트의 순서를 정의하는 방법

 

Little Endian(인텔)

  • 가장 작은 의미의 바이트(LSB)를 가장 낮은 주소에 저장.
  • 큰 의미의 바이트(MSB)는 더 높은 주소에 저장.

 

 

예제 (32비트 데이터: 0x12345678):

메모리 주소: [0]   [1]   [2]   [3]
저장 값:    0x78  0x56  0x34  0x12

 

특징

 

  • Intel x86 계열 CPU가 Little Endian을 사용.
  • 하드웨어에서 낮은 주소부터 읽을 때 효율적.

 

 

 

 

Big Endian(모토로라)

  • 최상위 바이트(Most Significant Byte, MSB)가 가장 낮은 메모리 주소에 저장.
  • 하위 바이트(LSB)는 더 높은 주소에 저장.

 

예제 (32비트 데이터: 0x12345678):

메모리 주소: [0]   [1]   [2]   [3]
저장 값:    0x12  0x34  0x56  0x78

 

 

특징

  • 네트워크 프로토콜(TCP/IP)은 Big Endian을 사용 (네트워크 바이트 순서).
  • 사람이 숫자를 읽는 방식과 유사하여 이해하기 쉬움.