2012-07-27 85 views
0

是的我知道,對double值進行按位操作似乎是一個壞主意,但我確實需要它。C++通過長長指針中斷輸出雙位輸入

你並不需要閱讀我的問題下一段落,只爲好奇你們的:

其實我嘗試一種特殊的MOD給Mozilla的Tamarin(ActionScript虛擬機)。其中,任何對象都有爲其類型保留的前3位(例如,double是7)。這些位降低了原始數據類型的精度(int只有29位等)。對於我的國防部,我需要擴大這個區域2位。這意味着,例如,當您添加2個雙打時,您需要將最後5位設置爲零,進行數學運算,然後將結果重置。那麼爲什麼^^

現在回到代碼。 這裏最小例子示出了非常類似的問題:

double *d = new double; 
*d = 15.25; 
printf("float: %f\n", *d); 

//forced hex output of double 
printf("forced bitwise of double: "); 
unsigned char * c = (unsigned char *) d; 
int i; 
for (i = sizeof (double)-1; i >=0 ; i--) { 
    printf ("%02X ", c[i]); 
} 
printf ("\n"); 

//cast to long long-pointer, so that bitops become possible 
long long * l = (long long*)d; 
//now the bitops: 
printf("IntHex: %016X, float: %f\n", *l, *(double*)l); //this output is wrong! 
*l = *l | 0x07; 
printf("last 3 bits set to 1: %016X, float: %f\n", *l, *d);//this output is wrong! 
*l = *l | 0x18; 
printf("2 bits more set to 1: %016X, float: %f\n", *l, *d);//this output is wrong! 

在VisualStudio2008運行此時,第一輸出是正確的。第二。 3rd對於十六進制和浮點數表示都會產生0,這顯然是錯誤的。 4th和5th對於十六進制和浮點數也都爲零,但修改後的比特以十六進制值顯示。所以我想,也許這個類型混淆了這裏的事情。所以2個輸出:

printf("float2: %f\n", *(double*)(long long*)d); //almost right 
printf("float3: %f\n", *d); //almost right 

很好,他們表現出15.25,但它應該是15.2500000000000550670620214078。所以我想,嘿,這只是輸出中的精確問題。允許修改位進一步向上:

*l = *l |= 0x10000000000; 
printf("float4: %f\n", *d); 

再次,輸出是15.25(0000),和不15.2519531250000550670620214078。奇怪的是,另一個強制十六進制輸出(見上面的代碼)根本沒有顯示d的修改。所以我修了一下,意識到第31位(0x80000000)是我手動設置的最後一個。和神聖莫里,它實際上對輸出有影響(15.250004)!

所以,雖然我略有偏差,仍然有很多混亂。 printf被破壞了嗎?我在這裏有一個大/小端的困惑嗎?我無意中創建了某種緩衝區溢出?

如果有人有興趣,在原來的問題(ta thing的事情,見上文),這幾乎是相反的。在那裏,最後三位已經被設置(表示雙倍)。將它們設置爲零可以正常工作(這是最初的實現)。將2更多地設置爲零具有與上述相同的效果(總體值被置爲零)。順便說一下,它不是特定於輸出的,而且數學運算似乎可以與這些地形數值一起工作(得到的2個數值的mul結果爲0)。

任何幫助,將不勝感激。 問候。

回答

4

很好,他們表現出15.25,但它應該是15.2500000000000550670620214078

默認情況下,%f顯示精度6位,所以你會看不出來區別。您還需要使用ll修飾符指定第一個參數是long long而不是int;否則,它可能會打印垃圾。如果你解決這個問題,並使用更高的精度,如%.30f,你應該看到預期的結果:

printf("last 3 bits set to 1: %016llX, float: %.30f\n", *l, *d); 
printf("2 bits more set to 1: %016llX, float: %.30f\n", *l, *d); 

last 3 bits set to 1: 0000000000000007, float: 15.250000000000012434497875801753 
2 bits more set to 1: 000000000000001F, float: 15.250000000000055067062021407764 

允許修改位進一步上漲:

*l = *l |= 0x10000000000; 
printf("float4: %f\n", *d); 

你有一個流氓=給未定義的行爲,所以值可能會或可能不會最終被修改(和程序可能會或可能不會崩潰,打電話給披薩,或破壞宇宙)。此外,如果您的編譯器不符合C++ 11標準,則整型文本的類型可能不大於long,該類型可能只有32位;在這種情況下,它可能(可能)變成零。

固定的(在我的情況下,你的代碼,因爲它是),我得到預期的結果:

*l = *l | 0x10000000000LL; // just one assignment, and "LL" to force "long long" 
printf("float4: %f\n", *d); 


float4: 15.251953 

Here是一個演示。

+0

謝謝邁克。那個流氓=實際上是一個複製粘貼錯誤,我發現在寫這個問題的時候並沒有在這裏糾正它。 LL是我以前不知道的東西,所以非常感謝。 有什麼奇怪的是:當我把這些%.30f放在printf的時候,他們沒有再顯示0.0,但實際上是15.25。 – 2012-07-27 11:04:15

0

您在printf參數中有錯誤。如果您傳遞8byte值,則必須使用 %llx而不是%x。

使用

printf("last 3 bits set to 1: %llX, float: %f\n", *l, *d); 
*l = *l | 0x18; 
printf("2 bits more set to 1: %llX, float: %f\n", *l, *d); 

,你的代碼將工作

+0

取消,我有一個litte錯誤,你的權利!謝謝! – 2012-07-27 11:20:31

0

在32位常量不能大於長(32位),所以你不能這樣做:

*l |= 0x10000000000;

您必須創建一個變量,然後將其移位。

long long ll = 1; 
ll <= 32; 
*l |= ll; 
+0

這種說法是錯誤的。 – 2012-07-27 10:49:18

+0

@ManuelAmstutz:這對於C++ 03是正確的;沒有定義「long long」,所以整數文字不能大於long,這在很多平臺上都是32位。在C++ 11中,如果對於較小類型的值太大,整數文字可以具有「long long」類型。 – 2012-07-27 10:53:29

+0

好的,我的評論是非常不準確的。 Sascha寫道他正在使用VS2008。對於所有VC版本從2003 - 2010 long long是相當於__int64: – 2012-07-27 11:10:57