2011-07-27 7 views
1

버그가 발견되어 (몇 시간 후) 다음 프로그램에서 분리되었습니다. 문제는 struct에 대한 포인터를 사용할 때 pst2 변수의 값이 계산되는 방식입니다. char에 대한 포인터를 사용하면 모든 것이 잘 동작합니다. 왜 이런거야?
(궁금해하는 사람들을 위해. : 나는 일반 오프셋에서 데이터 그룹을 포함하는 파일 버퍼를 액세스하는거야)C++ 포인터 연산 이상한

#include <iostream> 
#include "testpa.h" 

#pragma pack(push) 
#pragma pack(1) 
//--------------------------- 
struct st_one 
{ 
    int i; 
    char c; 
}; 
//--------------------------- 
struct st_two 
{ 
    long l; 
    int i; 
}; 
#pragma pack(pop) 

//=========================== 
int main() 
{ 
    int n=1024, np1=sizeof(st_one); //, np2=sizeof(st_two); 
    st_one *pst1, *pst1a; 
    st_two *pst2, *pst2a; 
    char *pc1, *pc2, *pc1a, *pc2a, *pb; 

    pb = new char[n]; 

    pst1 = (st_one*)(pb); 
    pst2 = (st_two*)(pst1 + np1); //using pst1 
    pc1 = (char*)(pb); 
    pc2 = (char*)(pc1 + np1); //using pc1 

    pst1a = (st_one*)(pb); 
    pst2a = (st_two*)(pb + np1); //using pb 
    pc1a = (char*)(pb); 
    pc2a = (char*)(pb + np1); //using pb 

    std::cout << "\npb = " << (long)pb; 
    std::cout << "\n-----"; 
    std::cout << "\npst1 = " << (long)pst1 << "\tpst2 = " << (long)pst2; 
    std::cout << "\npc1 = " << (long)pc1 << "\tpc2 = " << (long)pc2; 
    std::cout << "\n-----"; 
    std::cout << "\npst1a = " << (long)pst1a << "\tpst2a = " << (long)pst2a; 
    std::cout << "\npc1a = " << (long)pc1a << "\tpc2a = " << (long)pc2a; 
    std::cout << "\n-----\n"; 

    return 0; 
} 
: ((데비안 4.4.5-8) 4.4.5 ++ 버전의 gcc/g를 사용)

출력 : 나에게 잘 보이는

pb = 19546128 

pst1 = 19546128   pst2 = 19546153 <--- WRONG! 
pc1 = 19546128   pc2 = 19546133 

pst1a = 19546128  pst2a = 19546133 
pc1a = 19546128  pc2a = 19546133 
+0

내가 그 잘못 표시되지 않습니다. 어떤 행동을 기대합니까? –

+0

그건 어려운 방법입니다. 'pst1 [offset] .c'의 문제점은 무엇입니까? 컴파일러가 작업을 수행하게하십시오. 어쨌든 포인터 연산을 수행 할 것이므로 오류가 발생하기 쉽습니다. – msw

답변

8

. 라인 :

(pst1 + np1) 

pst1의 값이 25 np1 * sizeof (st_one) 바이트 씩 증가되는 것을 의미에서 무엇을 pst1st_onenp1 인스턴스를 추가합니다 (sizeof 연산자 = 5), 당신은했습니다 값에 해당하는 출력. 그는 char 포인터이기 때문에

(pst1 + 1) 

pc1 값이 작동하므로 선이 : 대신 위의, 나는 당신이 원하는 생각

(pc1 + np1) 

는 5 바이트 인 pc1np1 * sizeof (char) 바이트를 추가합니다.

포인터를 증가 시키면 포인터가 다음 바이트가 아니라 메모리의 다음 요소를 가리 킵니다.

+0

나는 외부 조작이 완료되기 전에 항상 괄호 안의 값이 먼저 계산된다는 인상을 받았다. 이 경우에는 pst1과 np1의 정수 값이 포인터로 형변환되기 전에 추가 될 것이라고 생각했을 것입니다. – slashmais

+0

아아! 나는 내가 실수 한 곳을 강조했다 - 고마워. – slashmais

3

sizeof(x)은 자동으로 수행되므로 추가하지 마십시오. ++ p와 같이 포인터를 증가 시키면 주소가 오브젝트 크기만큼 증가하여 다음 주소를 가리 킵니다.

포인터에 1을 더하면 ++ p와 같습니다. sizeof(x)을 추가하면 증분이 두 번 조정됩니다. 를 sizeof (문자)를 사용하면 잘못된 모든 것을 가지고 마치 1

1

때문에

귀하의 계산은, 문자에 대한 잘 작동합니다. 예를 들어, PST1에서 가져 오기 pst2에 대한 포인터 pst1 유형 st_one *입니다 당신은 하나를 증가해야한다, 그래서 당신은 다음과 같이 작성해야합니다 :

pst2 = (st_two*)(pst1 + 1);

을 ...하지만 당신은이 :

그 구조는 바이트를 갖는 한 그만큼 st_one 구조를 건너 뛸 수 있도록 NP1이 st_onesizeof이다

pst2 = (st_two*)(pst1 + np1);

...

this one과 같은 포인터 연산에 대한 일부 문서를 읽으십시오.

+0

좋아요, 읽을 것입니다 - 고마워요. – slashmais

2

C++은 추가 할 정수에 포인터가 가리키는 요소의 크기를 자동으로 곱합니다. 포인터를 바이트가 아닌 전체 요소로 전진시키고 자한다고 가정합니다.

2

C 및 C++에서의 포인터 산술은 포인터의 유형을 가리키는 포인터 sizeof 번을 수행합니다. 즉 int *abc = /* ... */; int *def = abc + 1의 결과는 def이고 이 아닌 보다 앞에 int이 표시됩니다.

long으로 포인터를 전송하는 것은 구현 정의 동작이므로 다른 컴퓨터에서 이상한 결과가 발생할 수 있습니다.

는 (그 문제에, 그래서 포인터 타입 사이에 캐스팅이다. C++는 너무 정의 된 구현 말한다)