programing

이 오프셋 구현이 작동하는 이유는 무엇입니까?

javamemo 2023. 8. 8. 19:56
반응형

이 오프셋 구현이 작동하는 이유는 무엇입니까?

ANSIC에서 오프셋은 다음과 같이 정의됩니다.

#define offsetof(st, m) \
    ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

NULL 포인터를 다시 참조하고 있는데 분할 오류가 발생하지 않는 이유는 무엇입니까?아니면 이것은 일종의 컴파일러 해킹인가요? 오프셋의 주소만 빼내어 실제로 참조를 다시 하지 않고 정적으로 주소를 계산하는 것입니다.또한 이 코드는 휴대용입니까?

위 코드의 어느 지점에서도 참조되지 않은 것은 없습니다.참조 해제는 다음과 같은 경우에 발생합니다.*또는->참조된 값을 찾기 위해 주소 값에 사용됩니다.*위는 주조를 목적으로 하는 형식 선언입니다.

->연산자는 위에서 사용되지만 값에 액세스하는 데 사용되지 않습니다.대신 값의 주소를 가져오는 데 사용됩니다.여기 매크로가 아닌 코드 샘플이 있습니다. 이 샘플을 사용하면 좀 더 명확해질 수 있습니다.

SomeType *pSomeType = GetTheValue();
int* pMember = &(pSomeType->SomeIntMember);

두 번째 줄은 실제로 참조 취소(구현에 따라 다름)를 유발하지 않습니다.단순히 주소를 반환합니다.SomeIntMember의내의 범위 에서.pSomeTypevalue.value.value.

임의의 유형과 문자 포인터 사이에 많은 캐스팅이 표시됩니다.char의 이유는 명시적인 크기를 가진 C89 표준의 유일한 유형(아마도 유일) 중 하나이기 때문입니다.사이즈는 1입니다.위의 코드는 크기가 1인지 확인함으로써 값의 실제 오프셋을 계산하는 사악한 마법을 사용할 수 있습니다.

이 비록그일구인만지의 이지만,offsetof다음과 같은 표준에 의해 의무화되지 않았습니다.

는 표준 헤더 " 다및매가표로헤있습다니어의음되정에 .<stddef.h>[...]

offsetof(type,member-designator)

유형이 있는 정수 상수 식으로 확장됩니다.size_t이 값은 구조체의 시작점(에 의해 지정됨)부터 구조체 부재(에 의해 지정됨)까지의 오프셋(바이트 단위)입니다.형식 및 구성원 지정자는 다음과 같이 되어야 합니다.

statictypet;

에 그다에그표현음ion▁express▁the▁then그라는 표현이&(t.member-designator)주소 상수로 평가됩니다. (지정한 멤버가 비트 필드인 경우 동작은 정의되지 않습니다.)

Plauger의 Standard C Library"와 PJ Plauger의 "The Standard C Library"의 의 " Standard C Library"를.<stddef.h>이 기능들은 모두 적절한 언어로 제공될 수 있으며(해야 합니까?) 특별한 컴파일러 지원이 필요할 수 있습니다.

이지만, 저는 했습니다. ( 제가 그의 ANSIC에서 입니다.offsetof하지만 제가 수정했을 때는 효과가 있었습니다.

#define offsetof(st, m) ((size_t)((char *)&((st *)(1024))->m - (char *)1024))

그것은 일종의 컴파일러 버그였는데, 특히 헤더가 컴파일러와 함께 배포되어 작동하지 않았기 때문입니다.

ANSIC 서에에서,offsetof그렇게 정의되지 않았습니다.이렇게 정의되지 않은 이유 중 하나는 일부 환경에서 null 포인터 예외가 발생하거나 다른 방식으로 충돌할 수 있기 때문입니다.는 "ANSIC"의 .offsetof( )컴파일러 작성자에게 공개됩니다.

위에 표시된 코드는 NULL 포인터를 적극적으로 확인하지 않지만 NULL 포인터에서 바이트를 읽을 때만 실패하는 컴파일러/환경에 일반적입니다.

질문의 마지막 부분에 답하기 위해 코드를 휴대할 수 없습니다.

두 포인터를 뺀 결과는 두 포인터가 동일한 배열의 객체를 가리키거나 배열의 마지막 객체(7.6.2 Additive Operators, H&S Fifth Edition)를 가리킬 때만 정의되고 이동 가능합니다.

1:인 목록 1: 대인일련의의 offsetof() 정의

// Keil 8051 compiler
#define offsetof(s,m) (size_t)&(((s *)0)->m)

// Microsoft x86 compiler (version 7)
#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)

// Diab Coldfire compiler
#define offsetof(s,memb) ((size_t)((char *)&((s *)0)->memb-(char *)0))

typedef struct 
{
    int     i;
    float   f;
    char    c;
} SFOO;

int main(void)
{
  printf("Offset of 'f' is %zu\n", offsetof(SFOO, f));
}

매크로 내의 다양한 연산자는 다음 단계를 수행하는 순서로 평가됩니다.

  1. ((s *)0)하여 정을 0 사여 에대포캐로다니합스팅터인에 대한 합니다.s.
  2. ((s *)0)->m 구성원을 를 취소합니다.m.
  3. &(((s *)0)->m)의 주소를 합니다.m.
  4. (size_t)&(((s *)0)->m)는 결과를 적절한 데이터 유형으로 캐스팅합니다.

정의에 따라 구조 자체는 주소 0에 상주합니다.따라서 (위의 3단계)를 가리키는 필드의 주소는 구조체의 시작 부분으로부터의 오프셋(바이트)이어야 합니다.

그것은 당신이 그것을 무시하지 않기 때문에 흠잡을 데가 없습니다.포인터 주소가 메모리 작업을 처리하는 데 사용되지 않고 다른 숫자에서 뺀 숫자로 사용되고 있습니다.

부의오을계산의 합니다.m유형의 개체 표현의 시작 주소에 상대적입니다.st.

((st *)(0))을 .NULL 타입의 st *.&((st *)(0))->m이 개체에 있는 멤버 m의 주소를 나타냅니다.이 개체의 시작 주소는 다음과 같습니다.0 (NULL)멤버 m의 주소는 정확히 오프셋입니다.

char *변환 및 차이를 통해 오프셋이 바이트 단위로 계산됩니다.포인터 작업에 따라 두 포인터 유형 사이에 차이를 만드는 경우T *결과는 유형의 객체 수입니다.T피연산자에 의해 포함된 두 주소 사이에 표현됩니다.

『 』 『 』 『 』의 C offsetof설정:

C 표준, 섹션 6.6, 제9항

는 정적 , 에 대한 로, null을 . 단항을 사용하여 명시적으로 생성되어야 합니다.&연산자 또는 정수 상수를 포인터 형식에 캐스팅하거나 배열 또는 함수 형식의 식을 사용하여 암시적으로 캐스트합니다.[] member-access 및원액스세성.그리고.-> 연자, 주소& 간접 간접적으 로로으.*단항 연산자, 포인터 캐스트는 주소 상수를 생성하는 데 사용될 수 있지만 객체의 값은 이러한 연산자를 사용하여 액세스할 수 없습니다.

매크로는 다음과 같이 정의됩니다.

#define offsetof(type, member)  ((size_t)&((type *)0)->member)

식은 주소 상수의 생성으로 구성됩니다.

실제로는 정적 저장 기간의 개체를 가리키지 않기 때문에 결과는 주소 상수가 아닙니다.그러나 이것은 객체의 값에 접근해서는 안 된다는 것에 여전히 동의하고 있기 때문에 포인터 유형에 캐스팅된 정수 상수는 무시되지 않습니다.

또한 C 표준의 다음 인용문도 고려해 보십시오.

C 표준, 섹션 7.19 제3항

형식 및 구성원 지정자는 다음과 같이 되어야 합니다.

static type t;

에 그다에그표현음ion▁express▁the▁then그라는 표현이&(t.member-designator)주소 상수로 평가됩니다. (지정한 멤버가 비트 필드인 경우 동작은 정의되지 않습니다.)

C의 구조체는 메모리 블록에서 하나의 이름 아래에 있는 변수의 물리적으로 그룹화된 목록을 정의하는 복합 데이터 유형(또는 레코드) 선언이며, 단일 포인터 또는 동일한 주소를 반환하는 구조체 선언 이름을 통해 서로 다른 변수에 액세스할 수 있습니다.

컴파일러 관점에서 구조체 선언 이름은 주소이고 구성원 지정자는 해당 주소의 오프셋입니다.

언급URL : https://stackoverflow.com/questions/713963/why-does-this-implementation-of-offsetof-work

반응형