2014-01-26 54 views
0

我寫的東西像Java,和我有指針的問題( - - ) 我有一個結構:C++不可能的指針行爲

struct _lnHeader32 
{ unsigned char signature[2]; //LN 
    unsigned char architecture; 
    unsigned int length; //Without _lnHeader 
    unsigned int lnHeaderLength; 
    unsigned char permissions; 
    unsigned char typeOfExecutable; 
    unsigned int flowSegment; 
    unsigned int dataSegment; 
    unsigned int loaderSegment; 
    unsigned int cleanerSegment; 
    unsigned int errorSegment; 
    unsigned int exportTable; 
    unsigned int importTable; 
    unsigned int authenticationTable; //Encrypt it with GPG. 
    unsigned int loaderTable; 
}; 

我打開可執行文件,它是在小尾數,由使用std :: fstream的:

lnFile.open(argv[1], std::fstream::in | std::fstream::binary); 
if (false == lnFile.is_open()) 
throw (unableToOpen); 
lnSize = getFileSize(lnFile); 
lnImage = new (std::nothrow) unsigned char [lnSize]; 
if (0 == lnImage) 
throw (noMem); 
lnFile.read(reinterpret_cast<char*>(lnImage), lnSize); //#1 Possible mistake? 
if (!lnFile) 
throw (unableToRead); 
lnFile.close(); 

然後我點_lnHeader32 *來分配lnImage:

lnHeader32 = reinterpret_cast<_lnHeader32*>(lnImage); 

在最後我通過兩種方法打印整個結構:

//Method 1 
std::cout << reinterpret_cast<unsigned int*>(lnImage) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+2) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+3) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+7) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+11) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+12) << "\n\n"; 

//Method 2  
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->signature) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->architecture) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->length) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->lnHeaderLength) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->permissions) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->typeOfExecutable) 
                    << "\n\n"; 

它給了我像輸出:

0xe8b260 
0xe8b262 
0xe8b263 <--- 
0xe8b267 
0xe8b26b 
0xe8b26c 

0xe8b260 
0xe8b262 
0xe8b264 <--- Should be 0xe8b263 | Here starts problem 
0xe8b268 
0xe8b26c 
0xe8b26d 

它通過使用第一種方法打印以及lnHeader32的領域,但我更喜歡使用第二種方法。我計算了一切幾次。爲什麼會發生? 可執行文件是由perl編譯器生成的,對它有什麼影響?

+5

https://en.wikipedia.org/wiki/Data_padding –

+0

使用nothrow new,只檢查結果爲null,然後拋出是一個真正的WTF? –

+0

現在一切都很好。謝謝你,Oli Charlesworth。 – SysOp

回答

3

由於填充(見https://en.wikipedia.org/wiki/Data_padding),你的結構實際上是這樣的:

struct _lnHeader32 { 
    unsigned char signature[2]; //LN 
    unsigned char architecture; 
    unsigned char PADDING[1];//so next member will be aligned by 4 
    unsigned int length; //Without _lnHeader 
    unsigned int lnHeaderLength; 
    unsigned char permissions; 
    unsigned char typeOfExecutable; 
    unsigned char PADDING[2];//so next member will be aligned by 4 
    unsigned int flowSegment; 
    unsigned int dataSegment; 
    unsigned int loaderSegment; 
    unsigned int cleanerSegment; 
    unsigned int errorSegment; 
    unsigned int exportTable; 
    unsigned int importTable; 
    unsigned int authenticationTable; //Encrypt it with GPG. 
    unsigned int loaderTable; 
}; 
1

的C字段++內存類型是沒有必要的連續,有一定的規則,當編譯器領域之間引入填充控制。

不同類型的字段通常對齊在預先確定的邊界。在這種情況下, char具有1個字節的大小,並且它是1對齊的,int具有4個字節的大小並且它是4對齊的。 (你可以找到更多關於這個here的細節)。

所以,你的結構是要像這樣在內存

0: signature[0] 
1: signature[1] 
2: architecture 
3: PADDING! 
4: first byte of length 
... 

而你得到的,因爲填充的長度字段中的值不正確。

我建議你不要將原始數據讀入內存,並重新將其解釋爲某種類型。這可能是非常危險的,因爲你很難確定你的編譯器如何將你的類型與內存對齊。

一個更爲安全的解決方案是創建一個輔助功能,如

_lnHeader32 readLnHeader32(const char* binary); 

,並在此功能由一個從文件中讀取二進制流中讀取的_lnHeader32結構一個領域。