구조체 선언 시 패딩 바이트는 정말 불필요한가?

'혼공 C언어' 구조체(struct)의 메모리 할당 이해

by Younggi Seo





Medium(영문 버전) | https://medium.com/@gonoah8/are-padding-bytes-really-unnecessary-when-declaring-a-structure-26f65acc9ee6


본문의 소스 코드는 위의 링크에서 다운로드할 수 있다.




이 글은 '테크니컬 라이팅'으로 아래와 같은 순서로 전개합니다.
1. 문제 제기

2. 문제 분석
1) 실제 메모리 구조
2) '패딩 바이트(padding byte)'란?
3) 패딩 바이트의 무쓸모 이론

3. 솔루션
1) 패딩 바이트의 유쓸모
2) 실무에 적용(결론)



1. 문제 제기

임베디드 프로그래머(*펌웨어 개발자)가 코딩한 펌웨어(프로그램)를 실행시킬 때, 컴파일러가 메모리에 할당하는 구조체의 멤버 변수들이 어떤 순서를 가지는지 알고 있다면, 패딩(padding)*까지 고려해 볼 수 있다. 아래 그림에서 패딩은 컴파일러가 자체적으로 정렬을 시키기 위해 사이사이에 일종의 더미(dummy) 상태의 메모리를 일컫는다. 이 남는 메모리 수를 합해서 '패딩 바이트(padding byte)'라고 불린다. 그럼 메모리 공간만 잡아먹는 이 패딩 바이트는 정말 불필요한가?

가장 큰 멤버 변수, grade(더블 데이터 타입)를 기준으로 멤버 변수들이 메모리에 할당된 구조


* 펌웨어(Firmware) : 하드웨어 내 ROM(메모리)에 내장되어 해당 기기를 직접 구동·제어하는 '하드웨어용 소프트웨어'. ATM의 내장 PC, 가전제품, IoT 기기 등에서 운영체제(OS) 없이 단독으로 하드웨어를 제어하며, 기능 추가나 오류 수정을 위해 업데이트(롤백하면 디운그레이드)가 가능.


2. 문제 분석

1) 패딩 바이트 정렬(Alignment)


ARM-32bit 시스템인 예를 들면(근래 거의 모든 시스템은 64bit), 아래의 저장공간이 할당된 메모리 구조처럼 서로 다른 특정 변수들이 기준이 되는 메모리 크기(단위) 내에서 차례대로 정렬되지 않으면(Misaligned) 시스템이 느려질 수 있다는 게 정설처럼 굳혀져 있다.

출처 : https://dev.to/amanprasad/structure-padding-isnt-wastage-of-memory-its-a-hardware-requirement..


2) '패딩 바이트(padding byte)'란?

위의 소스 코드를 보면 선언한 구조체(struct)의 멤버들은 간단해 보인다. int형 데이터(4 byte) 필드 한 개와 doube형 데이터(8 byte) 필드 하나로 구성되어 있다. 크기를 수동으로 더하면 12 바이트가 된다. 하지만, 실제로 전체 구조체의 크기를 확인하면, 16바이트다. 중간에 패딩 바이트 4바이트가 끼어져 있다는 의미다.


3) 패딩 바이트의 무쓸모 이론

중간에 쓸모없이 끼워져 있는 패딩 바이트로 시스템 혹은 네트워크 송신 간에 쓰이는 패킷*의 크기만 잡아먹으므로 통신이 느려질 수 있다는 이론은 실제로 패딩이 불필요하다고만 생각하게 만든다. 그래서 아래와 같은 헤더를 추가해서 패딩을 애초부터 사용하지 않도록 하는 경우가 있다.

#pragma pack(1) 헤더 설정으로 패딩을 제거하는 순간...


패킹은 실제로 메모리 레이아웃에만 영향을 미치고 CPU 동작에는 영향을 주지 않는다.

구조체를 패킹(pragma pack)할 때:

패딩 바이트가 제거된다.

멀티바이트 필드는 정렬이 어긋날 수 있다.

struct 크기가 작아진다. (메모리 낭비 해소)


변하지 않는 것:

CPU가 메모리를 가져오는 방법

아키텍처의 정렬 요구 사항

잘못된 접근으로 인한 비용

CPU는 여전히 정렬된 데이터를 기대하지만, 패킹 처리는 단순히 컴파일러의 안전장치를 제거하는 것뿐이다.



그래서 패딩은 오히려 필요하다.


* 패킷(packet) : 컴퓨터 네트워크를 통해 전송되는 데이터를 작은 조각으로 나눈 전송 단위. 큰 데이터를 소포(Package)처럼 여러 패킷으로 분할하여 전송하고 목적지에서 다시 재조립하며, 실제 데이터(페이로드)와 주소 정보(헤더)로 구성되어 효율적인 네트워크 전송을 가능하게 함.


3. 솔루션


1) 패딩 바이트의 유쓸모


패딩을 제거하면 아래와 같은 비용을 감수해야 할 수도 있다.

멀티바이트 필드는 정렬이 어긋날 수 있다.

CPU는 하나의 변수를 읽기 위해 여러 번(*사이클)의 메모리 읽기가 필요할 수 있다.

값을 조립하려면 추가 지침이 필요하다.

일부 아키텍처에서는 정렬이 잘못된 접근으로 인해 트랩이 발생하거나 시스템이 충돌할 수 있다. 다시 말해, 바이트 수는 절약되지만 처리 능력은 저하된다.

* 사이클(Cycle) : 클럭 주기(Clock Period) 또는 클럭 사이클은 컴퓨터의 CPU가 동작하는 기본 시간 단위로, 1번의 클럭 신호(high-low)가 완료되는 데 걸리는 시간. 피코초(ps)나 나노초(ns) 단위로 측정되며, 이 주기가 짧을수록 1초에 더 많은 명령어를 처리할 수 있어 CPU 성능이 향상됨.


그러므로 패딩을 제거하는 패킹처리를 하지 말고, 자료형 크기가 큰 데이터 순으로 멤버를 선언하자.




2) 실무에 적용(결론)

구조체 멤버 변수의 선언 순서만 바꿨을 뿐인데, 아키텍처의 효율성과 안전성을 제고할 수 있다.




참조

1)

2)