[c] 전 처리기 매크로에서 “sizeof”를 어떻게 사용할 수 있습니까?

sizeof전 처리기 매크로에서 를 사용하는 방법이 있습니까?

예를 들어, 몇 년 동안 제가 다음과 같은 일을하고 싶었던 많은 상황이있었습니다.

#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif

내가 여기서 확인하는 정확한 것은 완전히 구성되어 있습니다. 요점은 종종 이러한 유형의 (크기 또는 정렬) 컴파일 타임 검사를 삽입하여 잘못 정렬되거나 재정렬 될 수있는 데이터 구조를 수정하는 사람을 보호합니다. 그것들을 깨뜨릴 크기의 것들.

말할 필요도없이 sizeof위에서 설명한 방식으로 a를 사용할 수없는 것 같습니다 .



답변

이를 수행하는 방법에는 여러 가지가 있습니다. 다음 스 니펫은 sizeof(someThing)같으면 코드를 생성하지 않습니다 PAGE_SIZE. 그렇지 않으면 컴파일 타임 오류가 발생합니다.

1. C11 방법

C11부터 사용할 수 있습니다 static_assert(필요 #include <assert.h>).

용법:

static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size");

2. 맞춤 매크로

sizeof(something)예상 한 것과 다를 때 컴파일 타임 오류가 발생하면 다음 매크로를 사용할 수 있습니다.

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

용법:

BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );

이 기사에서는 작동 이유를 자세히 설명합니다.

3. MS 특정

Microsoft C ++ 컴파일러 에서는 섹션 2에서 설명한 것과 유사한 트릭을 사용하는 C_ASSERT 매크로 (필요 #include <windows.h>)를 사용할 수 있습니다 .

용법:

C_ASSERT(sizeof(someThing) == PAGE_SIZE);


답변

어쨌든 sizeof전 처리기 매크로에서 ” ” 를 사용할 수 있습니까?

아니요. 조건부 지시문은 제한된 조건식 집합을 사용합니다. sizeof허용되지 않는 것 중 하나입니다.

전처리 지시문은 소스가 (적어도 개념적으로) 구문 분석되기 전에 평가되므로 아직 크기를 가져 오지 못한 유형이나 변수가 없습니다.

그러나 C에서 컴파일 타임 어설 션을 얻는 기술이 있습니다 (예 : 이 페이지 참조 ).


답변

나는 그것이 늦은 대답이라는 것을 알고 있지만 Mike의 버전에 추가하기 위해 여기에 메모리를 할당하지 않는 버전이 있습니다. 원래 크기 확인을하지 않았고, 몇 년 전에 인터넷에서 찾았고, 안타깝게도 저자를 참조 할 수 없습니다. 다른 두 가지는 동일한 아이디어의 확장입니다.

typedef이기 때문에 아무것도 할당되지 않습니다. 이름에 __LINE__이 있으면 항상 다른 이름이므로 필요한 곳에 복사하여 붙여 넣을 수 있습니다. 이것은 MS Visual Studio C 컴파일러 및 GCC Arm 컴파일러에서 작동합니다. CodeWarrior에서는 작동하지 않으며 CW는 __LINE__ 전 처리기 구조를 사용하지 않고 재정의에 대해 불평합니다.

//Check overall structure size
typedef char p__LINE__[ (sizeof(PARS) == 4184) ? 1 : -1];

//check 8 byte alignment for flash write or similar
typedef char p__LINE__[ ((sizeof(PARS) % 8) == 0) ? 1 : 1];

//check offset in structure to ensure a piece didn't move
typedef char p__LINE__[ (offsetof(PARS, SUB_PARS) == 912) ? 1 : -1];


답변

이 스레드는 정말 오래되었지만 …

내 솔루션 :

extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];

해당 표현식이 0과 같으면 제대로 컴파일됩니다. 다른 것은 바로 거기에서 폭발합니다. 변수가 extern’d이기 때문에 공간을 차지하지 않으며 아무도 참조하지 않는 한 링크 오류가 발생하지 않습니다.

assert 매크로만큼 유연하지는 않지만 내 버전의 GCC에서 컴파일 할 수 없었고 이것은 거의 모든 곳에서 컴파일 될 것이라고 생각합니다.


답변

기존 답변은 유형의 크기에 따라 “컴파일 타임 어설 션”의 효과를 얻는 방법을 보여줍니다. 이 특별한 경우 OP의 요구를 충족시킬 수 있지만 유형의 크기에 따라 조건부 전처리 기가 실제로 필요한 다른 경우가 있습니다. 방법은 다음과 같습니다.

다음과 같은 작은 C 프로그램을 작성하십시오.

/* you could call this sizeof_int.c if you like... */
#include <stdio.h>
/* 'int' is just an example, it could be any other type */
int main(void) { printf("%zd", sizeof(int); }

컴파일하십시오. 위의 C 프로그램을 실행하고 출력을 캡처하는 좋아하는 스크립팅 언어로 스크립트를 작성하십시오. 해당 출력을 사용하여 C 헤더 파일을 생성하십시오. 예를 들어 Ruby를 사용 중이라면 다음과 같이 보일 수 있습니다.

sizeof_int = `./sizeof_int`
File.open('include/sizes.h','w') { |f| f.write(<<HEADER) }
/* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */
#define SIZEOF_INT #{sizeof_int}
/* others can go here... */
HEADER

그런 다음 Makefile 또는 기타 빌드 스크립트에 규칙을 추가하면 위의 스크립트를 실행하여 sizes.h.

sizes.h크기에 따라 전 처리기 조건을 사용해야하는 모든 곳에 포함 합니다.

끝난!

( ./configure && make프로그램을 빌드하기 위해 타이핑 한 적이 있습니까? configure기본적으로 위와 같은 스크립트는 무엇입니까? )


답변

다음 매크로는 어떻습니까?

/*
 * Simple compile time assertion.
 * Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
 */
#define CT_ASSERT(exp, message_identifier) \
    struct compile_time_assertion { \
        char message_identifier : 8 + !(exp); \
    }

예를 들어 MSVC는 다음과 같이 말합니다.

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits


답변

이 토론에 대한 참조로 일부 컴파일러는 sizeof () ar 전 처리기 시간을 얻습니다.

JamesMcNellis 대답은 정확하지만 일부 컴파일러는이 제한을 통과합니다 (이것은 아마도 엄격한 ansi c를 위반할 것입니다).

이 경우 IAR C- 컴파일러 (아마 전문적인 마이크로 컨트롤러 / 임베디드 프로그래밍의 선두 주자)를 언급합니다.