[英]Strange result with pointer casting
我正在測試是否可以在同一個數組中包含 int 和 float 值,我編寫了以下代碼:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int v[4]={0,0,0,0};
*((float*)(&v[1]))=45.6;
printf("%f\n",*((float*)(&v[1])));
printf("%f\n",v[1]);
return 0;
}
我期望有 45.599998 和 0 或在 printf 上有相同的值,但我得到不同的結果:45.599998 45.599983 為什么?,發生了什么?
編輯
順便說一句,我想強調的是,對於這個問題,我對執行此操作的替代方法不感興趣,我更感興趣的是了解為什么不起作用。
在示例代碼中,正如注釋中指出的那樣,調用了未定義的行為。 (在這種情況下,我認為違反了嚴格的別名。)
“[是否] 可以在同一個數組中包含int
和float
值”
不是在C
,任何type
的array
只能包含一種類型。 但是,如果這種安排的變體適合您,則可以在復合類型的單個實例中定義這兩種類型,例如struct
數組。 例如:
typedef struct {
int iVal;
float fVal;
} val_s;
val_s val[10];
現在您有一個包含10
val_s
類型元素的val_s
,其中每個元素都包含int
和float
類型成員。
C
中復合類型的另一個變體(已在評論中向我指出,這可能是您正在尋找的更多內容)是內置C
類型,它允許多種類型共享相同的內存,是union 。 需要注意的是,由程序員來跟蹤最后寫入哪個成員,因為在任何給定時間只有一個成員可以包含一個值......
例子:
typedef union {
int iVal;
float fVal;
} val_s;
val_s val;
我期望有 45.599998 和 0 或在 printf 上有相同的值,但我得到不同的結果:45.599998 45.599983 為什么?,發生了什么?
假設我們通過使用此變體消除了代碼中的一些未定義行為:
#include <string.h>
#include <stdio.h>
int main() {
int v[4]={0,0,0,0};
float f = 45.6;
memcpy(&v[1], &f, sizeof f);
printf("%f\n", f);
printf("%f\n", v[1]);
return 0;
}
這仍然具有未定義的行為,因為格式指令%f
沒有與v[1]
正確類型匹配,但是只要float
不大於int
,並且int
沒有陷阱表示(這兩個都適用於大多數C 實現)。
即使在f
和v[1]
的值具有相同的字節序列表示的可能情況下,它們的類型之間的差異對該代碼具有重要的影響。 諸如printf
之類的可變參數函數的變量參數受“默認參數提升”的約束。 這些使int
類型的值保持不變,但它們將float
s 提升為double
類型。 因此,如果您的float
和double
在實踐中不同,它們通常會這樣做,那么
printf
在兩種情況下接收不同的參數值,即使只考慮每個參數的字節序列,並且v[1]
情況下, printf
可能沒有收到足夠寬的值。 因此,如果您想沉迷於假設程序在這種未定義行為的情況下實際做了什么的可疑實踐,那么更有可能的可能性之一是,在v[1]
情況下,它查看float
的字節序列,結合一些恰好在內存中的額外隨機字節,將它們解釋為double
的字節,並且,幸運地和所選測試值的詳細信息,它提出了一個數值接近,但不完全匹配您的float
被提升到的double
float
。
使用浮點說明符並傳遞整數值以滿足格式字符串中的該參數是未定義的行為,也就是說,所有賭注都已關閉。
許多系統以完全不同的方式傳遞整數參數和浮點參數; 有些沒有。 “為什么”不能完全回答。 您碰巧在一個系統上,它的調用約定似乎並沒有以不同的方式傳遞整數和浮點參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.