문제

다음과 같이 테스트 구조 정의가 있습니다.

struct test{
    int a, b, c;
    bool d, e;
    int f;
    long g, h;
};

그리고 어딘가에 나는 이런 식으로 사용합니다.

test* t = new test;   // create the testing struct
int* ptr = (int*) t;
ptr[2] = 15;          // directly manipulate the third word
cout << t->c;         // look if it really affected the third integer

이것은 내 창문에서 올바르게 작동합니다. 예상대로 15 인쇄하지만 안전합니까? 변수가 메모리의 현장에 있다고 확신 할 수 있습니까? 원하는 결합 된 스트러크의 경우 직접적으로 원시적으로 (예 : F는 내 컴파일러에 다섯 번째 단어이지만 6 번째 변수입니까)?

그렇지 않은 경우, 코드에 실제로 구조물> 멤버 구성이 없으면 구조물 멤버를 직접 조작하는 다른 방법이 있습니까?

도움이 되었습니까?

해결책

두 가지 질문을하는 것 같습니다

3 길이의 int arrray로 치료 및 테스트하는 것이 안전합니까?

이것을 피하는 것이 가장 좋습니다. 이것은 C ++ 표준에서 정의 된 조치 일 수 있지만, 그렇지 않더라도 함께 일하는 모든 사람이 여기서하고있는 일을 이해할 가능성은 낮습니다. 스트러크를 패드 할 수있는 잠재력 때문에 표준을 읽으면 이것이 지원되지 않는다고 생각하지만 확실하지 않습니다.

이름이없는 회원에게 액세스하는 더 좋은 방법이 있습니까?

예. 사용해보십시오 오프셋 매크로/운영자. 이렇게하면 구조 내 특정 멤버의 메모리 오프셋을 제공하며 해당 멤버에게 지점을 올바르게 배치 할 수 있습니다.

size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);

또 다른 방법은 C의 주소를 직접 가져 오는 것입니다.

int* pointerToC = &(someTest->c);

다른 팁

아니오 확실하지 않습니다. 컴파일러는 구조 부재 사이에 패딩을 자유롭게 소개 할 수 있습니다.

추가합니다 Jaredpar의 대답, C ++의 또 다른 옵션 (일반 C가 아님)은 포인터 투 관련 객체를 만드는 것입니다.

struct test
{
  int a, b, c;
  bool d, e;
  int f;
  long g, h;
};

int main(void)
{
  test t1, t2;

  int test::*p;  // declare p as pointing to an int member of test
  p = &test::c;  // p now points to 'c', but it's not associating with an object
  t1->*p = 3;    // sets t1.c to 3
  t2->*p = 4;    // sets t2.c to 4

  p = &test::f;
  t1->*p = 5;    // sets t1.f to 5
  t2->*p = 6;    // sets t2.f to 6
}

당신은 아마도 offsetof 매크로. 이렇게하면 멤버의 바이트 오프셋이 제공됩니다. 그런 다음 해당 오프셋에서 멤버를 조작 할 수 있습니다. 그러나이 매크로는 구현에 따라 다릅니다. 포함 stddef.h 작동하기 위해.

아마도 안전하지 않으며 100% 읽을 수 없습니다. 따라서 실제 생산 코드에서 이러한 종류의 코드를 용납 할 수 없게 만듭니다.

세트 메소드와 부스트를 사용하십시오 ::이 변수를 변경할 수있는 functor를 만들기위한 바인드.

패딩/정렬 문제 외에 다른 답변이 제기 된 것 외에도 코드는 엄격한 별칭 규칙을 위반하므로 최적화 된 빌드에 대해서는 중단 될 수 있습니다 (MSVC 가이 작업을 수행하는 방법은 확실하지 않지만 GCC -O3 이러한 유형의 행동에서 깨질 것입니다). 본질적으로. 왜냐하면 test *t 그리고 int *ptr 유형이 다르고 컴파일러는 메모리의 다른 부분을 가리키고 있다고 가정 할 수 있으며 작동을 재정렬 할 수 있습니다.

이 사소한 수정을 고려하십시오.

test* t = new test;
int* ptr = (int*) t;

t->c = 13;
ptr[2] = 15;
cout << t->c;

끝의 출력도 마찬가지입니다 13 또는 15, 컴파일러가 사용하는 작동 순서에 따라.

표준의 9.2.17 항에 따르면, 실제로 구조물을 제공하는 첫 번째 멤버와의 포인터에 포인터 간 스트럭을 시전하는 것은 합법적입니다. 현물 상환 지불:

reinterpret_cast를 사용하여 적절하게 변환 된 포드 스트럭 객체에 대한 포인터는 초기 멤버를 가리 키십시오 (또는 해당 멤버가 비트 필드 인 경우, 그것이 상주하는 단위로) 그 반대도 마찬가지입니다. [참고 : 따라서 포드 스트럭 객체 내에 이름이없는 패딩이있을 수 있지만 적절한 정렬을 달성하기 위해 필요한 경우 처음에는 그렇지 않을 수 있습니다. ]

그러나 표준은 스트러크의 레이아웃 (심지어 POD 스트러크)에 대해 보장하지 않습니다.private:, protected: 또는 public:) 그들 사이에. 그래서, 당신의 초기 부분을 취급합니다 struct test 3 개의 정수 배열은 기술적으로 정의되지 않은 동작입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top