2009-05-28 2 views
4

기본적으로 포인터의 주소를 버퍼에 저장하고 싶습니다. 왜 묻지 마세요버퍼에 정수 복사하기 memcpy C++

char * buff = "myBuff"; 
char * myData = (char*)malloc(sizeof(char*)); 
int addressOfArgTwo = (unsigned int)buff; 
memcpy(myData, &addressOfArgTwo, sizeof(char*)); 

cout << "Int Val: " << addressOfArgTwo << endl; 
cout << "Address in buffer:" << (unsigned int)*myData << endl; 

위의 코드가 작동하지 않는 이유는 알 수 없습니다. 이것은 출력 :

Int Val: 4472832 
Address in buffer:0 

버퍼에 지능 브로 & 주소가 동일해야하는 경우. 덕분에

+0

감사합니다 당신의 도움에 대한 모든 –

답변

8

char *를 참조하고 char의 결과를 4 바이트의 전체 4 바이트가 아닌 int로 캐스팅합니다 (32 비트 시스템 인 경우 64 비트 시스템에서는 8 바이트) 비트). 4472832는 16 진수 444000입니다. 리틀 엔디 언 컴퓨터에서는 지난 00 일을 붙잡습니다.

*((unsigned int*)myData) 

결과로 올바른 숫자가 표시됩니다.

1
Instead of (int)*myData, it should be *((int*)myData) 
1

마이클은이 선이 일반적으로 위험

cout << "Address in buffer:" << *((unsigned int*)myData) << endl 
1

을해야합니다 말했듯 :

*((unsigned int*)myData) 
IA-32 (모두가 사용되는 것을)이 정렬되지 않은 액세스를 지원하는 인텔

하지만, 다른 아키텍처는 그렇지 않습니다. 변수를 정렬해야합니다 (1 바이트 경계의 8 비트 데이터, 2 바이트 경계의 16 비트 데이터 및 4 바이트 경계의 32 비트 데이터). 정렬이 필요한 아키텍처에서 정렬되지 않은 액세스는 손상된 데이터를 반환하거나 CPU 예외를 throw합니다. 이전 작업에서 실제로 발생한 버그를 보았습니다. 임베디드 플랫폼에서 사용중인 소프트웨어 패키지와 함께 제공된 디스크 드라이버 때문에 파일 시스템 손상을 일으키는 미묘한 버그입니다.

고립 된 경우 myData의 주소가 malloc()에서 왔음을 알 수 있습니다. 이는 모든 유형의 포인터에 대해 적절하게 정렬되어 있음을 의미하지만 더 큰 포인터에 작은 포인터를 캐스팅하는 것은 일반적으로 위험한 사례입니다. 포인터가 어디서 왔는지 모릅니다.

unsigned int GetUnalignedLittleEndianUInt32(void *address) 
{ 
    unsigned char *uc_address = (unsigned char *)address; 
    return (
     (uc_address[3] << 24) | 
     (uc_address[2] << 16) | 
     (uc_address[1] << 8) | 
     uc_address[0] 
    ); 
} 
:

임의의 메모리 위치로부터 32 비트 정수를 추출하는 안전한 방법은 원시 문자 배열로 소스 메모리 처리, 임시 32 비트 정수를 선언하고 그것을 카피를 수행하는 것

또는 더 일반적으로 (일부 함수 호출 오버 헤드) : 실제로 방어 적이기의 정반대입니다

unsigned int GetUnalignedUInt32(void *address) 
{ 
    unsigned int value; 
    memcpy(&value, address, sizeof(value)); 
    return value; 
} 

()는 당신이 처음에이 포인터를 얻을 수 있었다.

int로 포인터를 치료, 비록 : 마이클 지적대로, 32 비트 및 64 비트 아키텍처 사이를 이동하는 경우

int addressOfArgTwo = (unsigned int)buff; 

는 또한 위험하다. 포인터는 항상 32 비트 정수가 아닙니다. 나중에 변경할 수있는 typedef를 사용해보십시오. Linux의 관례는 포인터가 long과 같은 크기가되도록하는 것입니다. Windows에는 typedefs INT_PTR, UINT_PTR, LONG_PTR 및 ULONG_PTR이 있습니다.

그래서, 나는 마침내 (어쨌든 Windows에서) 제안 :

ULONG_PTR GetAddressAtAddress(void *address) 
{ 
    ULONG_PTR value; 
    memcpy(&value, address, sizeof(value)); 
    return value; 
}