[임베디드 C] Padding & Bit 파싱
구조체 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 데이터 시트
문서 규칙/용어
- rw : Read/Write
- r : Read Only
- w : Write Only
- t : 1만 넣어도 토글됨
- Res : Reserved, 사용금지, 0으로 유지할것
추가 용어들은 데이터시트 p45
확인
메모리 구조
메모리 지도 4GB 주소 공간이 있지만, 20KB 정도의 일부만 사용한다.
맵핑된 메모리 주소와 연결한다. 핀에 따라
각각의 메모리 주소를 가지게 된다.
여러 장치들이 메모리 맵에 맵핑되어 있는데, 장치의 첫번째 주소가 0x0000이 아닐 수 있다.
해당 메모리 맵핑의 주소를 알면
동작 시킬 수 있고 상태 확인이 가능하다.
사용하지 않은 남은 부분은 Reserved 영역
이라 한다.
데이터시트의 메모리맵
을 보면 H/W의 메모리 주소가 어디인지 알 수 있다.
Author And Source
이 문제에 관하여([임베디드 C] Padding & Bit 파싱), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dev-hoon/임베디드-C-r6fy7e03저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)