linyunwen
raygoah
contributed by <LinYunWen
, raygoah
>
已知在 x86_64 架構,以下程式碼的執行輸出是 jserv++C
:
#include <stdio.h>
int main() {
puts((char *) &(double []){ 3823806048287157.0, 96 });
}
考慮以下程式碼,假設 puts 函式總是可正確運作,那麼程式輸出為何?
#include <stdio.h>
double m[] = { 3823806048287157.0, 96 };
void gen() {
if (m[1]--) {
m[0] *= 2;
gen();
} else
puts((char *) m);
}
int main() { gen(); return 0; }
首先先將 3823806048287157.0 以二進位表示,根據 IEEE754 double 的儲存方式如下圖,因此我們先將 3823806048287157 轉成二進位
以科學符號表示為
將小數點後的所有值拿出來從 fraction 的 high bit 開始放
(最後面補上一個 0 )
+ 51
= 1023 + 51
=
=
放進 exponent 裏
(前面要補上 0)
因此完成結果為01000011 00101011 00101011 01110110 01110010 01100101 01110011 01101010
因為強制轉型成 char * ,因此接著要將這一長串 0 和 1 轉換成 char ,因此將每 8 個 bits 一組形成一個字元,最後呈現的結果便是 C++vresj
,但是因為使用的機器其儲存方式為 little-endian,所以顯示的結果會相反:jserv++C
可以看到在 gen() 中,會將 m[0] 的值乘上 2,而因為遞迴的關係,最後 m[0] 會乘上
對於乘上
延伸題目:
m[]
的內容變為你的英文姓氏 (last name),程式碼應該越短越好,而且不得以字串的形式存在於原始程式碼修改程式,允許輸出你的 GitHub 帳號名稱
#include <stdio.h>
int main() {
// output: raygoah
puts((char *) &(double []){ 1.08497298767257192667014240249E-306});
// output: LinYunWe
puts((char *) &(double []){ 1.5192075502270189308379629358E180});
}
修改 gen() 函式,透過特定的轉換,讓 m[]
的內容變為你的英文姓氏 (last name)
raygoah:
0 00000000110 1000011000010110111101100111011110010110000101110010
LEI_____:
0 10111110101 1111010111110101111101011111010010010100010101001100
由上面比較可知,sign bit 不變,而 exponent 需要加上 1519,因此乘上
乘完後,在次方相同的情況下,加上兩者的差距,即可順利轉換成要的結果
#include <stdio.h>
double m[] = { 1.08497298767257192667014240249E-306, 1519 };
void gen() {
if (m[1]--) {
m[0] *= 2;
gen();
} else {
m[0] = m[0] + (0.57218400314947140020383950500E151);
puts((char *) m);
}
}
int main() { gen(); return 0; }
在 big-endian 的環境中,要如何改寫
參考 stackoverflow 。也可以不改變數值,但是另外用一個函式ReverseFloat() 一個一個 char 轉過來。(注意網址中是只有32 bits ,因此只有 4個 char 空間,而若是適用於這題需要 0~7 ,8個空間。)
rex662624
在不更改程式碼的前提下,撰寫 Convert "Little-Endian" to "Big-Endian" 的函式,也是可行的做法:
自己撰寫一個:
workat60474
static void Little_to_Big_swap(void *v)
{
char in[8], out[8];
memcpy(in, v, 8);
out[0] = in[7];
out[1] = in[6];
out[2] = in[5];
out[3] = in[4];
out[4] = in[3];
out[5] = in[2];
out[6] = in[1];
out[7] = in[0];
memcpy(v, out, 8);
}