기본 콘텐츠로 건너뛰기

Template with #pragma pack bug

일반적으로 C/C++컴파일러는 메모리 퍼포먼스를 위해 구조체 멤버를 새로 순서를 정렬하거나 4바이트 단위로 패딩을 한다. 대부분의 컴파일러는 순서는 바꾸지 않고, 전체크기를 4바이트 단위로 패딩을 하는데, 일반상황에서는 크게 문제를 야기 하지 않는다.

그러나 File이나 Network에서 쓰일 고정길이 레코드 개념으로 쓰다보면 4바이트 단위 패딩은 매우 위험하다. 따라서 컴파일러마다 지시자를 두어 1바이트 단위로 패딩할 수 있게 하였다.

GCC는 __attribute__((__packed__)) 지시어를 이용하지만 GCC에만 적용하는 것이고, 일반적으로 VC에서 사용하던 지시자인 #pragma pack을 사용한다.

사용법은 아래와 같다.

#pragma pack(push, 1)

// ... definition ...

#pragma pack(pop)

또는

#pragma pack(1)

// ... definition ...

#pragma pack()

그런데 이러한 Data structure alignment가 Template과 결합하면 심각한 버그를 만들어낸다.

* 2002년에 보고한 내용인데, 2009년에 수정한 GNU GCC팀의 패기에 박수를 보낸다. (응?)


#include
using namespace std;

#pragma pack(1)
template<typename _T>
struct mystr_t
{
_T otype;
int i;
};
#pragma pack()

#pragma pack(1)
struct inner_t
{
char c[3];
};
#pragma pack()

int
main(int argc, char* argv[])
{
cout << "sizeof(inner_t): " << sizeof(inner_t) << endl;
mystr_t<inner_t> tmp;
cout << "sizeof(tmp): " << sizeof(tmp) << endl;

#pragma pack(1)
mystr_t<char[3]> tmp2;
cout << "sizeof(tmp2): " << sizeof(tmp2) << endl;
#pragma pack()

mystr_t<unsigned char[3]> tmp3;
cout << "sizeof(tmp3): " << sizeof(tmp3) << endl;
}

위 코드는 Template이 실제 코드로 구현(instantiatiion)할 때마다 pragma pack이 적용되어 어떠한 경우에도 "7"을 출력해야 정상이다. 그러나 버그가 있는 GCC는 2번째를 제외하고 모두 "8"을 출력한다.

버그이고, 회피 방법은 앞서 말한 __attribute__((__packed__))를 사용하는 방법이 있지만, 소스코드가 지져분해지고 매우 귀찮다. 아니면 GCC를 4.5.1 이후 버전을 사용하는 방법도 있다.

* 참고로 해당 버그가 GCC외에도 꽤 많은 C++ 컴파일러에 존재하였고, 현재는 유명한 컴파일러는 모두 수정한 상태이다.

댓글

이 블로그의 인기 게시물

버즈 라이브 배터리 교체

나는 버즈 라이브(SM-R180)가 좋은데, 평가가 별루였는지, 해당 스타일로 버즈를 더 이상 만들지 않고 있다. 아무튼, 오래 쓴 버즈 라이브 배터리가 슬슬 맛이 가기 시작해서, 블로그 를 참조하면서 분해 및 교체를 하였다. (진짜 쉬움) 요로코롬 위아래를 살짝 눌러주면 뚜껑이 벌어진다. 안쪽 플라스틱은 오른쪽은 분홍색, 왼쪽은 회색이다. 리본 케이블 살짝 들어내고, 기판을 떼어내면, 작은 나사가 있다. 나사를 풀고, 플라스틱을 걷어내면, 검은 양면 테이프로 고정된 CR1254 배터리가 보인다. 잘 쑤셔서(?) 꺼낸다. 새로운 CR1254 배터리를 넣는다. 음극이 아래로 가도록 하고, 분해의 역순으로 조립하면 된다. 조립할 때, 아까 풀었던 나사는 잊지 말고 꼭 조여준다. (까먹고 조립해서 다시 뜯고 조립함) 충전도 잘 되고, 소리도 잘 나는거 보면, 조립도 잘 된 것 같다. 이렇게 버즈 라이브의 수명을 강제로 늘렸다. 나중에 본체 배터리도 갈아야겠다.

Windows 에서 절전을 깨우는 장치 찾기

참조:  https://www.reddit.com/r/computer/comments/wquswv/windows_11_pc_wakes_up_every_time_i_move_usb/ powercfg /devicequery wake_armed powercfg /deviceenablewake "[DEVICE]" # $PROFILE function Get-WakeArmedDevices { $devices = powercfg -devicequery wake_armed if ($devices) { $devices | ForEach-Object { $_.Trim() } } else { Write-Host "No devices are currently armed for wake events." } } function Set-EnableWakeOnDevice { param( [string]$deviceName ) sudo powercfg -deviceenablewake $deviceName } function Set-DisableWakeOnDevice { param( [string]$deviceName ) sudo powercfg -devicedisablewake $deviceName }