[英]Pointers and type casting in C
假設我有以下C代碼
#include<stdio.h>
int main()
{
float a=3.14;
char j= a;
printf("%d\n", j);
return 0;
}
輸出 :3(按預期)
現在假設我使用指針執行相同的操作。
#include<stdio.h>
int main()
{
float a=3.14;
char *j= (char*)&a;
printf("%d\n", *j);
return 0;
}
輸出 :-61
現在為什么我得到-61而不是3
編輯從到目前為止的答案中,我了解到,由於char(通常)的長度為1個字節,所以char指針僅選擇第一個字節並給出-61而不是打印完整的float。
但是,在這里,編譯器如何確定數據類型的大小,以便它知道必須停止打印的位置。到目前為止,它會由指針類型決定嗎?
但是理想情況下,在編譯的詞法階段,會創建符號表,並且那時還可以理解數據類型。
問題所以,如果我說使用字符指針編譯器,“嘿,伙計!只需打印您找到由我給出的字符指針指向的位置的數據(類型)。”它應該然后,打印完整的浮法正如編譯器現在知道的那樣,它是一個浮點數。
char *j= (char*)&a;
現在j
指向a
的第一個字節,它本身可能是四個字節長。
printf("%d\n", *j);
在這里,您將a
的基礎表示形式中的第一個字節的值作為int傳遞。
根據IEEE 754,這是0x4048f5c3
的第一個字節( 在此處檢查)。 假設您的計算機是0xc3
字節序,則得到0xc3
。 您的char
已簽名,因此得到0x100-0xc3
= 61
。
關於您的編輯:您不要求編譯器打印指針指向的數據類型。 編譯器可以可靠地獲得的有關此地址內容的唯一信息是其具有的靜態類型,即char
。 C中沒有對類型信息的運行時支持。
偶然地 ,編譯器可能知道該內存區域恰好是一個float
(因為它很聰明和/或您給出了一個退化的示例),但這可能僅對警告和優化有所幫助; 這個相同的情況怎么樣?
void foo(char* j)
{
printf("%d\n", *j);
}
// perhaps in a translation unit:
int main()
{
float a=3.14;
foo((char*)&a);
return 0;
}
在這種情況下,您明確要求他將這個內存區域視為一個字符,因此它確實可以執行此操作,並且沒有任何警告。
因為您已經從正確的類型轉換(應該收到有關截斷的警告)轉變為一種按位分配的情況。 當您只選擇一個內存表示形式的第一個字節而不進行某種形式的語義轉換時,所有賭注都關閉了。
您強制轉換了指針,但是在變量“ a”中引用的數據仍然浮動。 因此,打印不正確。 您需要在打印之前強制轉換數據:
printf("%d\n", (int)(*(float*)(void*)j));
這里是代碼的描述:
#include<stdio.h>
int main()
{
float a=3.14;
聲明一個float
類型的變量a
,並在其中放入3.14,根據IEEE754浮點數表示,該變量為0x4048f5c3。 ( http://www.binaryconvert.com/result_float.html?decimal=051046049052 )因此,基本上,在內存中,您有4個字節:0x4048f5c3
char *j= (char*)&a;
您聲明一個指針,該指針指向包含0xc3的a
的第一個字節(取決於系統字節的內部表示形式)。 由於j
是char*
,因此您會忘記所有其他字節。
printf("%d\n", *j);
0xc3是-61(表示已簽名的字符)( http://www.binaryconvert.com/result_signed_char.html?decimal=045054049 )
return 0;
}
但是,在第一種情況下,您寫char j = a;
, a
被正確地鑄造。
當然,如果將j
轉換為float*
,則可以訪問完整的數字:
#include <stdio.h>
int main()
{
float a=3.14;
char *j= (char*)&a;
printf("%d\n", *j);
printf("%f\n", *((float*)j));
return 0;
}
將打印:
-61
3.140000
第一個代碼段涉及一種類型到另一種類型的轉換 ; 當您為j
分配3.14
時,編譯器會將值的表示形式從浮點格式(在我的系統上為0xc3f54840
)更改為char
格式( 0x03
)。 請記住,將浮點值轉換為整數值時,小數部分會被截斷。
在第二個片段中,您將更改對解釋存儲在中的值a
。 您正在傳遞
一個指向
第一個字節的值的
指針
(值0xc3
)。 由於printf
是可變函數,因此它將char
類型的值提升為int
。 由於設置了0xc3
的高位,因此它將值符號擴展到0xffffffc3
,即-65。
對於傻笑,我編寫了以下代碼來演示如何在內存1中表示不同的值:
#include <stdio.h>
int main( void )
{
float a = 3.14;
char j = a;
unsigned char ju = a;
char *jp = (char *) &a;
unsigned char *jpu = (unsigned char *) &a;
union { float a; unsigned char b[sizeof (float)]; } bytes;
bytes.a = a;
printf( "a = %f\n", a );
printf( "j = %d\n", j );
printf( "ju = %u\n", ju );
printf( "*jp = %d (%02x) \n", (char) *jp, (char) *jp );
printf( "*jpu = %u (%02x) \n", (unsigned char) *jpu, (unsigned char )*jpu );
printf( "a representation = " );
for ( size_t i = 0; i < sizeof bytes.a; i++ )
{
printf( "%02x ", bytes.b[i] );
}
putchar( '\n' );
printf( "j representation = %02x\n", j );
printf( "ju representation = %02x\n", ju );
return 0;
}
在我的系統上得到了以下結果:
a = 3.140000 j = 3 ju = 3 *jp = -61 (ffffffc3) *jpu = 195 (c3) a representation = c3 f5 48 40 j representation = 03 ju representation = 03
浮點變量的值應使用浮點指令解釋,因為它使用某些浮點標准(例如IEEE 754 )存儲在內存中。
但是對char *的類型轉換將使用通用整數指令&來解釋它,而該指令不知道這種表示法,因此結果是不確定的。
類型轉換為char將導致使用浮點數到整數的轉換指令,結果將是浮點變量的尾數部分(除非它溢出目標變量大小)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.