2012-09-17 2 views
1

현재 내가 겪고있는 문제를 정확히 설명하는 방법을 알지 못했기 때문에 질문 제목에 모호한 경우 미안합니다.알 수없는 유형의 변수에 대한 포인터를 역 참조

지금 내가하는 것은 변수에 저장되는 가상 주소의 목록입니다. 예를 들어, 나는 문자 변수에 저장

0x8c334dd

을 보내고 있습니다. 이 주소는 데이터가있는 다른 변수의 주소입니다. 내가하고 싶은 것은 그 주소로 가서 거기에 저장된 데이터를 얻는 것입니다.

내 가정은 포인터를 역 참조하는 것이 최선의 방법이었을 것입니다. 불행히도 주소가 가리키는 변수의 유형을 모르므로 역 참조가이 경우 어떻게 작동합니까? 할 수 없습니다 : 주소가 가리키는 변수의 유형을 모르기 때문에 *(char *) 8c334dd을 입력 했으므로 ...

(int *)으로 변환하면 일부 주소의 일부 데이터 (여러 주소가 있음을 기억하십시오)하지만 다른 주소는 주소를 얻고 있으며 데이터 (이 변수는 구조체, 문자 등)가 필요합니다. 나는 ELF 기호 표 일반적으로

+1

'char a = * (char *) 0x8c334dd;' – ouah

+0

내 가정은 포인터를 역 참조하는 것이 여기에서 작동하지 않는다는 것입니다. 왜냐하면 주소가있는 변수를 역 참조하면 그것은 두 번째 변수의 내용이 아니라 콘텐츠 (동일한 주소 임)가 될 것입니다. 맞습니까? 또한 데이터를 가져 오려는 변수의 유형이 무엇인지 모르겠다. – attis

+1

응? "두 번째 변수"는 무엇입니까? 포인터를 역 참조하는 경우 해당 주소에 저장된 내용을 가져옵니다. (또한 C 질문 인 경우 왜 C++ 태그가 붙습니까?) –

답변

3

, C++ 또는 C 함께 일하고

은 당신이 포인터의 유형을 알 방법이 없습니다.

이 문제를 해결하는 일반적인 방법은 포인터가 구조체를 가리키게하고 구조체의 알려진 위치에 데이터 형식을 나타내는 것입니다. 일반적으로 알려진 위치는 구조체의 첫 번째 위치입니다.

예 :

// signature value; use any value unlikely to happen by chance 
#define VAR_SIG 0x11223344 

typedef enum 
{ 
    vartypeInvalid = 0, 
    vartypeInt, 
    vartypeFloat, 
    vartypeDouble, 
    vartypeString, 
    vartypeMax // not a valid vartype 
} VARTYPE; 

typedef struct 
{ 
    VARTYPE type; 
#ifdef DEBUG 
    uint32_t sig; 
#endif // DEBUG 
    union data 
    { 
     int i; 
     float f; 
     double d; 
     char *s; 
    }; 
} VAR; 

당신은 다음 전성 검사를 수행 할 수 있습니다 type 필드가 vartypeInvalid 미만 vartypeMax보다 큰 값이 있는지를 알 수 있습니다 (당신은에서 그 이름을 편집 할 필요가 없습니다 것입니다 청결성 체크 코드를 입력하고, 더 많은 유형을 추가하면 목록에 vartypeMax 앞에 추가합니다. 또한 DEBUG 빌드의 경우 서명 필드 sig에 특정 서명 값이 포함되어 있는지 확인할 수 있습니다. (즉, 초기화 코드 VAR 인스턴스는 항상 sig 필드를 설정해야합니다.)

이렇게하면 초기화하는 방법은 무엇입니까? 런타임 코드는 항상 작동합니다 :

VAR v; 

#ifdef DEBUG 
v.sig = VAR_SIG; 
#endif // DEBUG 
v.type = vartypeFloat; 
v.data = 3.14f; 

컴파일 타임에 초기화 하시겠습니까?

VAR v = 
{ 
    vartypeInt, 
#ifdef DEBUG 
    VAR_SIG, 
#endif // DEBUG 
    1234 
}; 

당신이 C의 C99 호환 버전을 사용하는 경우, 당신이 실제로 가진 구조체를 초기화 할 수 있습니다 : 당신은 정수 값을 초기화 할 경우 int 유형이 union의 첫 번째 유형이 있기 때문에, 쉽게 필드 이름을 지정하고 모든 유형을 지정하십시오. 그러나 Microsoft C는 C99과 호환되지 않으므로 float 또는 double 값으로 구조체를 초기화하려는 경우 위의 사항은 악몽입니다.float 값을 정수로 변환하면 C는 유형을 변경하는 것이 아니라 값을 반올림하고 32 비트 정수 값을 올바르게 나타내는 32 비트 정수 값을 이식 할 수있는 트릭이 없습니다. C 프로그램의 컴파일시에 떠.)

Compile time float packing/punning

당신이 포인터로 작업하는 경우,하지만, 그건 간단합니다. 유니온의 첫 번째 필드 이름을 포인터 유형으로 만들고, 포인터를 void *으로 캐스팅하고 위와 같이 구조체를 초기화하십시오. 포인터는 1234이 위를 차지하는 곳으로 갈 것입니다.

타인의 코드로 작성된 테이블을 읽고 유형 식별자 필드를 추가 할 방법이없는 경우 일반적인 대답이 없습니다. 나는 당신이 다른 타입으로 포인터를 읽는 것을 시도 할 수 있었고, 어떤 것이 작동하는지 볼 수있을 것 같아요?

+0

도움이됩니다. 그리고 몇 가지 좋은 아이디어를 나에게주었습니다. 불행히도 테이블 값은 나와 함께 제공되지 않습니다. 필자는 ELF 심볼 테이블 값을 사용하여 프로그램에 전달 된 모든 프로그램을 "디 컴파일"하는 방법을 사용하고 있습니다.필자에게 ELF 기호 테이블을 제공함으로써 어떤 변수가 int 유형, char 유형 또는 struct 유형인지 공제 할 수 있어야하며 각각의 변수를 가져올 수 있어야합니다. 지금까지 내가 알 수없는 유형의 "어딘가"를 가리키는 주소는 엘프 심볼 테이블에서 얻을 수있는 주소 집합입니다. – attis

+0

실제로 다른 누군가의 테이블 인 API와 함께 작업하고 있습니다. ELF가 더 정확한 것으로 제안했습니다. 그리고 문제는 컴파일러가 형식이 유효하지 않다는 것에 대해 불평하지 않기 때문에 포인터의 유형을 추측하려고 시도하는 것이 무의미하다는 것입니다. 따라서 포인터를 char로 읽으려는 경우 임의의 비 ASCII char을 얻을 수 있습니다 값, 만약 내가 int로 값을 가리키는 실제 값 또는 다른 주소를 얻을 수도 읽고 그것을 시도 .. – attis

0

ELF 기호 테이블로 작업하는 사람들을 위해 뭔가 추가하고 싶었지만 DWARF 파일의 DIE가 더 쉽게 작동한다는 것을 알았습니다. ELF 대신 DWARF를 사용하여 변수의 주소, 유형 및 이름을 얻을 수 있으며 libdwarf에는 좋은 설명서가 있습니다.

관련 문제