source

구조 부재를 오프셋으로 가져오거나 설정하려면 어떻게 해야 합니까?

lovecheck 2023. 10. 29. 19:49
반응형

구조 부재를 오프셋으로 가져오거나 설정하려면 어떻게 해야 합니까?

패딩/정렬 문제를 무시하고 다음과 같은 구조를 고려할 때, 멤버 이름을 사용하지 않고 member_b 값을 얻고 설정하는 가장 좋은 방법은 무엇입니까?

struct mystruct {
    int member_a;
    int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));

다른 말로 하자면, 다음을 포인터/오프셋으로 어떻게 표현하시겠습니까?

s->member_b = 3;
printf("%i",s->member_b);

내 추측으로는

  • member_a의 크기를 구하여 오프셋을 계산합니다(int)
  • 구조를 단일 단어 포인터 유형으로 캐스트(char?)
  • 창조하다, 창안int포인터를 가리키고 주소를 설정합니다.*charpointer + offset?)
  • 내꺼 써요int메모리 내용을 설정할 포인터

하지만 나는 캐릭터 타입에 캐스팅하는 것에 대해 약간 혼란스러워하거나 아니면 비슷한 것을.memset더 적절하거나 일반적으로 제가 이것을 완전히 틀리게 접근하고 있습니다.

도움이 되시길 응원합니다.

당신이 개략적으로 설명한 접근 방식은 대략 정확하지만, 당신은 다음을 사용해야 합니다.offsetof스스로 상쇄를 파악하는 대신에 말입니다.왜 당신이 그 일을 언급하는지 잘 모르겠습니다.memset-- 블록의 내용을 지정된 값으로 설정합니다. 이 값은 당면한 질문과 전혀 관련이 없어 보입니다.

작동 방식을 설명하기 위한 코드는 다음과 같습니다.

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

typedef struct x {
    int member_a;
    int member_b;
} x;

int main() { 
    x *s = malloc(sizeof(x));
    char *base;
    size_t offset;
    int *b;

    // initialize both members to known values
    s->member_a = 1;
    s->member_b = 2;

    // get base address
    base = (char *)s;

    // and the offset to member_b
    offset = offsetof(x, member_b);

    // Compute address of member_b
    b = (int *)(base+offset);

    // write to member_b via our pointer
    *b = 10;

    // print out via name, to show it was changed to new value.
    printf("%d\n", s->member_b);
    return 0;
}

전체 기법:

  1. 다음의 오프셋을 사용하여 오프셋을 가져옵니다.

    b_offset =의 오프셋(struct my structor, member_b);

  2. 구조의 주소를 문자 * 포인터로 가져옵니다.

    char *sc = (char *)s;

  3. 구조물 주소에 간격띄우기 추가를 추가하고, 값을 포인터에 적절한 유형으로 캐스팅한 후 참조를 해제합니다.

    *(int *)(sc + b_offset)

패딩과 얼라인먼트를 무시한 채로 말입니다.

예에서와 같이 지시하는 요소가 전체적으로 단일 유형일 경우 구조를 원하는 유형으로 캐스트한 후 배열로 처리할 수 있습니다.

printf("%i", ((int *)(&s))[1]);

구조와 NULL을 기준 포인터로 하여 오프셋을 계산할 수 있습니다. 예를 들어 "&((타입 *)0)->필드"

예:

struct my_struct {
    int x;
    int y;
    int *m;
    int *h;
};
int main()
{
    printf("offset %d\n", (int) &((((struct my_struct*)0)->h)));
    return 0;
}

이 예에서는 다음을 통해 해결할 수 있습니다.*((int *) ((char *) s + sizeof(int))). 왜 그러시는지 잘 모르니 교훈적인 취지를 전제로 하고 있으니 설명을 따르겠습니다.

코드의 비트는 다음과 같이 번역됩니다: 주소에서 시작하는 메모리를 가져와 다음을 가리키는 메모리로 취급합니다.char. 해당 주소에 추가합니다.sizeof(int) char- chunks - 새 주소가 표시됩니다.주소가 생성한 값을 사용하여 다음과 같이 취급합니다.int.

주의할 점은 다음과 같습니다.*(s + sizeof(int))주소는 다음과 같습니다.s플러스로sizeof(int)(mystruct) 청크 크기

편집: Andrey의 코멘트에 따르면, 오프셋을 사용하여:

*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))

편집 2: 모두 교체했습니다.byte에 를 char잿더미로sizeof(char)1로 보장됩니다.

여러분이 실제로 하고 있는 일은 다양한 데이터 유형을 하나의 메모리 블록으로 포장하고 압축을 푸는 것입니다.직접 포인터 캐스트를 사용하면 이 작업에서 벗어날 수 있지만, 다른 대부분의 답변에서는 다음과 같이 제시하고 있습니다.

void set_int(void *block, size_t offset, int val)
{
    char *p = block;

    *(int *)(p + offset) = val;
}

int get_int(void *block, size_t offset)
{
    char *p = block;

    return *(int *)(p + offset);
}

문제는 이것이 휴대가 불가능하다는 것입니다.블록 내에 올바른 정렬 상태로 유형을 저장할 수 있는 일반적인 방법은 없으며, 일부 아키텍처에서는 정렬되지 않은 주소에 로드나 저장을 수행할 수 없습니다.블록의 레이아웃이 선언된 구조물로 정의되는 특수한 경우에는 구조물 레이아웃에 올바른 정렬을 보장하는 데 필요한 패딩이 포함되므로 괜찮습니다.하지만 이름으로 접속할 수 없기 때문에 이것은 실제로 당신이 하는 일이 아닌 것처럼 들립니다.

휴대용으로 이 작업을 수행하려면 다음을 사용해야 합니다.memcpy:

void set_int(void *block, size_t offset, int val)
{
    char *p = block;

    memcpy(p + offset, &val, sizeof val);
}

int get_int(void *block, size_t offset)
{
    char *p = block;
    int val;

    memcpy(&val, p + offset, sizeof val);
    return val;
}

(다른 유형과 유사함).

언급URL : https://stackoverflow.com/questions/2043871/how-can-i-get-set-a-struct-member-by-offset

반응형