2011-09-26 72 views
1

我試圖將char *再次加倍並轉換回char *。如果您創建的應用程序是32位,但不適用於64位應用程序,則以下代碼正常工作。當您嘗試從int轉換回char *時,會發生此問題。例如,如果hello = 0x000000013fcf7888,則轉換爲0x000000003fcf7888,只有最後的32位是正確的。char *再次加倍並返回char *(64位應用程序)

#include <iostream> 
#include <stdlib.h> 
#include <tchar.h> 
using namespace std; 


int _tmain(int argc, _TCHAR* argv[]){ 

    char* hello = "hello"; 
    unsigned int hello_to_int = (unsigned int)hello; 
    double hello_to_double = (double)hello_to_int; 

    cout<<hello<<endl; 
    cout<<hello_to_int<<"\n"<<hello_to_double<<endl; 

    unsigned int converted_int = (unsigned int)hello_to_double; 
    char* converted = reinterpret_cast<char*>(converted_int); 

    cout<<converted_int<<"\n"<<converted<<endl; 

    getchar(); 
    return 0; 
} 
+7

這些轉換是無用的和危險的(將*指針*轉換爲浮點數的想法讓我感到畏縮)。你應該避免它們。 –

+2

@ user965772你爲什麼這樣做? – Praetorian

+0

鑄造是非常危險的,當你理解它時... – hplbsh

回答

6

在64位Windows指針上是64位,而int是32位。這就是爲什麼在鑄造時你會丟失高32位的數據。而不是int使用long long來保存中間結果。

char* hello = "hello"; 
unsigned long long hello_to_int = (unsigned long long)hello; 

對逆向轉換做出類似的更改。但是,這並不能保證使轉換正常工作,因爲double可以很容易地表示整個32位整數範圍而不會損失精度,但對於64位整數也是如此。

而且,這是行不通的

unsigned int converted_int = (unsigned int)hello_to_double; 

這轉換將簡單地截斷任何數字的浮點表示小數點後。即使您將數據類型更改爲unsigned long long,也存在該問題。您需要登錄reinterpret_cast<unsigned long long>才能正常工作。

即使在您仍然可能遇到麻煩取決於指針的值。例如,轉換爲double可能會導致該值爲,例如NaN,導致您的代碼可能會引發異常。

簡單的答案是,除非您嘗試這個樂趣,否則不要做這樣的轉換。

+0

謝謝Praetorian ..這篇文章是非常有用的:) – int80h

0

只有最後的32位是正確的。

這是因爲您平臺上的int只有32位長。請注意,reinterpret_cast只保證您可以將指針轉換爲具有足夠大小的整型(不是您的情況),然後返回。

2

你不能投了char*int在64位的Windows,因爲int爲32位,而char*爲64位,因爲它是一個指針。由於double總是64位,因此您可以在doublechar*之間進行鑄造。

+0

不過,我認爲他不會用「大」指針值來避開它,因爲只有52位保留用於尾數。 –

+0

你*可以從'char *'轉換爲'int'。結果不一定有意義。 –

1

如果它適用於任何系統,任何地方,只要你自己幸運,繼續前進。將指針轉換爲整數是一回事(只要整數足夠大,就可以避開它),但double是浮點數 - 你所做的只是沒有意義,因爲double不一定能夠表示任何隨機數。雙重有範圍和精度限制,並限制它如何表示事物。它可以表示各種值的數字,但不能代表該範圍內的每個數字。

請記住,double有兩個分量:尾數和指數。總之,這些允許您表示非常大或非常小的數字,但尾數限制位數。如果尾數用完,你會失去一些你想要表達的數字。

顯然你在某些情況下逃避了它,但是你要求它做一些它沒有做的事情,而且它顯然是不適合的。

只是不這樣做 - 它不應該工作。

1

幾個問題用編碼成浮點值的任何整數(即,位的集合):從64位整數

  1. 換算到雙打可以是有損的。一個雙精度的實際精度爲53-bits,因此高於2^52的整數(給定或需要額外2個)不一定會精確表示。
  2. 如果您決定將指針的位重新解釋爲double而不是(通過unionreinterpret_cast),如果碰巧將指針編碼爲不是有效雙重表示的位集合,您仍然會遇到問題。除非可以保證double的值永遠不會被FPU寫回,否則FPU可以靜默地將無效double轉換爲另一個無效double(請參閱NaN),即一個表示相同值但具有不同位的double值。 (See this for issues related to using floating point formats as bits.)

你可以放心地編碼一個32位的指針在double中,因爲這肯定會在53位精度範圍內。

0

這是預期的。

通常,char*將在32位系統上爲32位,在64位系統上爲64位; double在兩個系統上通常都是64位。 (這些大小是典型的,對於Windows來說可能是正確的;語言允許更多的變化。)

據我所知,從指針到浮點類型的轉換是未定義的。這並不意味着轉換的結果是不確定的;嘗試執行此類轉換的程序的行爲未定義。如果幸運的話,該程序將崩潰或無法編譯。但是你正在從一個指針轉換爲一個整數(這是允許的,但實現定義),然後從一個整數到一個雙精度(這是允許和有意義的有意義的數值 - 但轉換後的指針值是不具有數字意義)。你失去了信息,因爲並不是所有的64位都用來表示數字的大小;通常使用11位左右來表示指數。

你在做什麼很簡單沒有意義。

你究竟想完成什麼?不管它是什麼,肯定有更好的方法來做到這一點。