[임베디드 C] Padding & Bit 파싱

정재훈·2022년 4월 5일
1

임베디드 C언어

목록 보기
10/11
post-thumbnail

구조체 Alignment (Padding)

해당 코드의 struct는 몇 바이트일까?

struct Node // 5byte??
{
	char a; // 1byte
    int b; // 4byte
};

8byte이다. CPU 내부 성능 UP을 위해 Padding을 사용한다.

CPU는 메모리 값을 4 Byte 단위로 읽을 수 있다. 내용이 잘려서 두번 읽는 것을 방지하기 위해 4Byte 단위로 정렬을 위해 적절한 빈공간을 두는 걸 Padding이라 한다.

구조체에서만 Padding을 사용한다.

패딩을 제거해야 원할한 파싱

컴파일러에게 패딩을 넣지 말라고 지시하는 명령어 : #pragma pack(1);
#pragma pack(4); : 패딩 넣을 것을 빼는 명령어

#include <stdio.h>

int main()
{
#pragma pack(1) // 패딩 사용하지 않겠다. => 출력 : 5 5
	struct Node1
	{
		char a;
		int t;
	};

// #pragma pack(4) //패딩 사용하겠다 => 출력 : 5 8
	struct Node2
	{
		char a;
		int t;
	};

	printf("%d\n",sizeof(struct Node1));
	printf("%d\n",sizeof(struct Node2));
	
	

	return 0;
}

비트필드

특정 bit만 사용하는 맴버변수이다. 4개의 예제를 통해 완벽히 이해해보자.

예제 1)

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

int main()
{
#pragma pack(1)
	struct Node
	{
		uint8_t a : 2;  // 8비트 중 2비트 사용
		uint8_t b : 5;  // 8비트 중 5비트 사용
		uint8_t c : 1; // 8비트 중 1비트 사용
        
        // 8비트 중 총 8비트 사용 => 8비트 : 1바이트
	};

	struct Node kfc = {1,3,1};

	printf("%d\n",sizeof(kfc)); // 1 [Byte] 


	return 0;
}

주소도 다음과 같이 확인할 수 있다.

예제 2)

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

int main()
{
#pragma pack(1)
	struct Node
	{
		uint8_t a : 2; // 8비트 중 2비트 사용
		uint8_t b : 5; // 8비트 중 5비트 사용
		uint8_t c : 2; // 8비트 중 2비트 사용
        
        // 8비트 중 총 9비트 사용 => 9비트 : 1바이트 + 1비트
	};

	struct Node kfc = {1,3,1};

	printf("%d\n",sizeof(kfc)); // 2 [Byte]


	return 0;
}

예제 3)

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

int main()
{
#pragma pack(1)
	struct Node
	{
		uint16_t a : 3; // 16비트 중 3비트 사용
		uint8_t b : 2; // 8비트 중 2비트 사용
		uint8_t c : 5; // 8비트 중 5비트 사용
        
        // 총 16비트 중 3비트 + 8비트 중 7비트 => 16비트(2바이트) + 8비트(1바이트)
	};

	struct Node kfc = {1,3,1};

	printf("%d\n",sizeof(kfc)); // 3 [Byte]


	return 0;
}

예제 4)

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

int main()
{
#pragma pack(1)
	struct Node
	{
		uint16_t a : 3; // 16비트 중 3비트 사용
		uint8_t b : 2; // 8비트 중 2비트 사용
		uint32_t c : 5; // 32비트 중 5비트 사용
        
        // 총 16비트 중 3비트 + 8비트 중 7비트 + 32비트 중 5비트
        // => 16비트(2바이트) + 8비트(1바이트) + 32비트(4바이트)
	};

	struct Node kfc = {1,3,1};

	printf("%d\n",sizeof(kfc)); // 7 [Byte]


	return 0;
}

비트 지칭하기

특정 비트를 지칭할 때 [큰 bit 번호 : 작은 bit 번호]

비트 파싱하기

1. memcpy

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

int main()
{
#pragma pack(1)

	uint8_t data = 0x73;  // 0111 0011

	struct Node
	{	
		// 0 1 11001 1
		uint8_t a : 1;  // 1
		uint8_t b : 5;  // 1 1001 
		uint8_t c : 1; // 1
		uint8_t d : 1; // 0
	};

	struct Node input;

	// struct에 data 복사하기
	memcpy(&input, &data, sizeof(data));

	printf("0x%02X\n",input.a); //%02X : 16진수를 2자리로 표현
	printf("0x%02X\n",input.b);
	printf("0x%02X\n",input.c);
	printf("0x%02X\n",input.d);


	return 0;
}

2. Union

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

int main()
{
#pragma pack(1)

	uint8_t data = 0x73;  // 0111 0011

	union Node
	{
		uint8_t origin; 
		// 리틀 엔디안 방식으로 0x37으로 저장
		struct // 유니온이라 구조체 또한 0x37로 저장
		{
			// struct 내부 구조로 나눌 때에는 또 리틀엔디안 방식으로 0x73형식으로 나누어짐
			// 0111 0011 => 0 1 11001 1
			uint8_t a : 1;  // 1
			uint8_t b : 5;  // 1 1001
			uint8_t c : 1; // 1
			uint8_t d : 1; // 0

		}field;
	};

	union Node input;

	input.origin = data; // orgin 변수에 data 값 넣기


	printf("0x%02X\n",input.field.a); //%02X : 16진수를 2자리로 표현
	printf("0x%02X\n",input.field.b);
	printf("0x%02X\n",input.field.c);
	printf("0x%02X\n",input.field.d);


	return 0;
}

데이터시트를 통한 파싱

데이터시트 분석 1

데이터 시트란 : 부품 제조사에서 만든 메뉴얼이다.
데이터 시트에서 P134
6 바이트에 대한 데이터가 들어오면, 다음과 같이 파싱 해야한다.

OPERATION CODE : 8 bit
Reserved : 3 bit <= (5~7 : 3bit)
Logical Block Address (LBA) : 21 bit <= (0~4 : 5bit + 2Byte(16bit))
Transfer Length : 8 bit
CONTROL : 8 bit

데이터시트 분석 2

살펴볼 칩셋 : STM32F103RB 데이터 시트

문서 규칙/용어

  1. rw : Read/Write
  2. r : Read Only
  3. w : Write Only
  4. t : 1만 넣어도 토글됨
  5. Res : Reserved, 사용금지, 0으로 유지할것

추가 용어들은 데이터시트 p45 확인

메모리 구조

메모리 지도 4GB 주소 공간이 있지만, 20KB 정도의 일부만 사용한다.
맵핑된 메모리 주소와 연결한다. 핀에 따라 각각의 메모리 주소를 가지게 된다.
여러 장치들이 메모리 맵에 맵핑되어 있는데, 장치의 첫번째 주소가 0x0000이 아닐 수 있다.
해당 메모리 맵핑의 주소를 알면 동작 시킬 수 있고 상태 확인이 가능하다.
사용하지 않은 남은 부분은 Reserved 영역이라 한다.
데이터시트의 메모리맵을 보면 H/W의 메모리 주소가 어디인지 알 수 있다.

profile
여러 방향으로 접근하는 개발자

0개의 댓글