전처리기 매크로에서 "sizeof"를 사용하는 방법
A을(를) 사용할 수 있는 방법이 있는가?sizeof
전처리기 매크로에서?
예를 들어, 몇 년 동안 다음과 같은 일을 하고 싶은 상황이 많이 있었다.
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
내가 여기서 확인하고 있는 정확한 것은 완전히 지어낸 것이다. 요점은, 나는 종종 데이터 구조를 잘못 조정하거나 그것들을 깨트릴 수 있는 크기를 재조정하는 사람을 경계하기 위해 이런 유형의 컴파일 타임 체크들을 넣기를 좋아한다.
말할 필요도 없이 - 나는 a를 사용할 수 없을 것 같다.sizeof
상술한 방법으로
이것을 하는 데는 여러 가지 방법이 있다.다음 스니펫은 다음과 같은 경우 코드가 생성되지 않는다.sizeof(someThing)
대등하다PAGE_SIZE
; 그렇지 않으면 컴파일 시간 오류가 발생한다.
1. C11길
C11부터 사용할 수 있음(필수)#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++ 컴파일러에서는 C_ASSert 매크로(필수)를 사용할 수 있음#include <windows.h>
)는 섹션 2에서 설명한 것과 유사한 트릭을 사용한다.
사용량:
C_ASSERT(sizeof(someThing) == PAGE_SIZE);
늦은 대답인 건 알지만 마이크의 버전에 덧붙이자면 여기 우리가 사용하는 버전이 있는데 어떤 메모리도 할당하지 않는다.나는 원래 사이즈 확인을 생각해내지 못했는데, 몇 년 전에 인터넷에서 찾았는데 아쉽게도 작가를 참조할 수가 없어.다른 두 사람은 같은 생각의 연장선에 불과하다.
그것들은 타이페프의 것이기 때문에, 아무것도 할당되지 않는다.이름에 _LINE__이 있으면, 필요한 곳에 복사하여 붙여넣을 수 있도록 항상 다른 이름이다.이것은 MS Visual Studio C 컴파일러와 GCC Arm 컴파일러에서 작동한다.CW는 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];
"를 사용할 수 있는 방법이 있는가?
sizeof
"이전 매크로에서?
아니다. 조건부 지시문은 제한된 조건부 표현식을 사용한다.sizeof
허용되지 않는 것 중 하나야
사전 처리 지시문은 선원을 구문 분석하기 전에 평가되므로(적어도 개념적으로), 아직 그 크기를 파악할 유형이나 변수가 없다.
그러나 C에는 컴파일 시간 주장을 얻는 기법이 있다(예: 이 페이지 참조).
기존 답변은 유형 규모에 따라 '비교적 시간 주장'의 효과를 얻는 방법만 보여준다.그것은 이 특별한 경우에 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 헤더 파일을 생성하십시오.예를 들어 루비를 사용하고 있다면 다음과 같이 보일 수 있다.
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
스크립트 실행은 기본적으로 위와 같다...)
C11에서_Static_assert
키워드가 추가된다.다음과 같이 사용할 수 있다.
_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn't match page size")
이 실이 정말 오래된 줄 알지만...
내 해결책:
extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];
그 표현이 0과 동일하다면, 그것은 괜찮다.다른 건 다 터지면 바로 저기서변수가 외부적이기 때문에 공간을 차지하지 않으며, 아무도 이를 참조하지 않는 한 링크 오류를 발생시키지 않을 것이다.
매크로처럼 유연하지는 않지만, 내 버전의 GCC에서 컴파일할 수 없었으니...어디서든 컴파일할 수 있을 것 같아
이 논의에 대한 참고자료로서, 나는 일부 컴파일러들이 사전 프로세서 시간 ()을 갖는다고 보고한다.
JamesMcNellis의 대답은 정확하지만, 일부 컴파일러들은 이러한 제한을 겪는다(이는 아마도 엄격한 ansi c를 위반할 것이다).
그 예로 IAR C-컴파일러(전문 마이크로컨트롤러/임베디드 프로그래밍의 선두주자일 가능성이 있음)를 언급한다.
다음 매크로:
/*
* 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
전처리기에는 연산자를 사용할 수 없지만, 전송할 수 있음sizeof
컴파일러로 이동하여 런타임에 상태를 확인하십시오.
#define elem_t double
#define compiler_size(x) sizeof(x)
elem_t n;
if (compiler_size(elem_t) == sizeof(int)) {
printf("%d",(int)n);
} else {
printf("%lf",(double)n);
}
#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
아마 효과가 있을 것이다.
나의 휴대용 c++ 코드 (http://www.starmessagesoftware.com/cpcclibrary/ )는 나의 구조체나 수업의 일부의 크기를 안전하게 보호하기를 원했다.
전처리가 에러를 던질 수 있는 방법(여기서 언급된 크기()로는 작동할 수 없는 것)을 찾는 대신에, 나는 여기서 컴파일러가 에러를 던지게 하는 해결책을 찾았다.http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
내 컴파일러(xcode)에 오류를 발생시키기 위해 그 코드를 조정해야 했다.
static union
{
char int8_t_incorrect[sizeof( int8_t) == 1 ? 1: -1];
char uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1];
char int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1];
char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1];
char int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1];
char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1];
};
언급된 매크로의 것을 시험해본 결과, 이 파편은 원하는 결과를 만들어 내는 것 같다().t.h
):
#include <sys/cdefs.h>
#define STATIC_ASSERT(condition) typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4);
STATIC_ASSERT(sizeof(int) == 42);
달리기cc -E t.h
:
# 1 "t.h"
...
# 2 "t.h" 2
typedef char _static_assert_3[ (sizeof(int) == 4) ? 1 : -1];
typedef char _static_assert_4[ (sizeof(int) == 42) ? 1 : -1];
달리기cc -o t.o t.h
:
% cc -o t.o t.h
t.h:4:1: error: '_static_assert_4' declared as an array with a negative size
STATIC_ASSERT(sizeof(int) == 42);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.h:2:84: note: expanded from macro 'STATIC_ASSERT'
...typedef char __CONCAT(_static_assert_, __LINE__)[ (condition) ? 1 : -1]
^~~~~~~~~~~~~~~~~~~~
1 error generated.
42는 결국 모든 것에 대한 해답이 아니다...
컴파일 시간에 데이터 구조의 크기를 제약조건과 비교하기 위해 나는 이 방법을 사용했다.
#if defined(__GNUC__)
{ char c1[sizeof(x)-MAX_SIZEOF_X-1]; } // brakets limit c1's scope
#else
{ char c1[sizeof(x)-MAX_SIZEOF_X]; }
#endif
x의 크기가 한계 MAX_SIZEOF_X보다 크거나 같으면 gcc는 '배열 크기가 너무 크다'는 오류로 불평할 것이다.VC++는 오류 C2148('배열의 총 크기가 0x7ffffffffff바이트를 초과하지 않아야 함') 또는 C4266 '상수 크기 0의 배열을 할당할 수 없음'을 발생시킨다.
gcc는 제로 사이즈의 배열을 이러한 방식으로 정의(x - n의 크기)할 수 있기 때문에 두 가지 정의가 필요하다.
참조URL: https://stackoverflow.com/questions/4079243/how-can-i-use-sizeof-in-a-preprocessor-macro
'programing' 카테고리의 다른 글
SRC, OBJ, BIN 하위 디렉터리를 사용하여 C 프로젝트의 Makefile을 생성하는 방법은? (0) | 2022.05.20 |
---|---|
부동소수점비교 (0) | 2022.05.20 |
Laravel Passport 미들웨어 보호 경로 "인증되지 않음" 문제 (0) | 2022.05.20 |
Vue 클로징 구성 요소 반환 시 프로펠러가 직접 변질되지 않도록 주의 (0) | 2022.05.19 |
Laravel 5.3에서 Vue.js 2.0 구성 요소에서 외부 html 템플릿을 사용하는 방법 (0) | 2022.05.19 |