2016-11-21 118 views
0

爲什麼此代碼輸出-32768而不是32768?看起來像一個溢出,但我不知道在哪裏。C神祕的溢出

#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ 
    char *buffer = (char*)malloc(sizeof(char)*2); 
    buffer[0] = 0x80; 
    buffer[1] = 0x00; 
    int address = (buffer[0]<<8) | (buffer[1]); 
    printf("%d\n", address); //outputs -32768 
    return 0; 
} 
+3

由於緩衝區[0]爲-128 – immibis

+0

哇哦,應該是無符號的不應該是 – danielmhanover

+0

的「int」是一個有符號的數字。如果高位被設置爲有符號整數,則表示它爲負。也許你應該谷歌「二補」。 – TonyB

回答

1

對您的編譯器char進行簽名。

在您的編譯器上,0x80轉換爲-0x80以適合簽署的char

因此buffer[0]保持-128,並且((-128)<<8) | (0)評估爲-32768。

+0

'( - 128)<< 8'評估爲未定義的行爲。 – Lundin

0

該代碼可以執行的幾種可能的方式。

  • char在你的編譯器上沒有簽名。然後該表達式將被評估爲0x80<<8 | 0x00,其給出0x8000。如果這適合您系統中的int,則結果將爲32768.否則,它將以某種實現定義的方式轉換爲帶符號格式。在二進制補碼計算機上,您可能會得到結果-32768。

  • char在您的編譯器上簽名。然後0x80不適合它,但在某些實現定義的方式中轉換爲負數。在二進制補碼計算機上,它可能會得到-128的值。然後,您左移這個負值 - 這會調用未定義的行爲(來源:C11 6.5.7/4)。這反過來可能導致任何事情發生:你的程序可能會崩潰或打印廢話,或者編譯器可能存在一些特定的非標準行爲,如將結果視爲-32768。

這裏的關鍵是,你不應該寫這樣的代碼,它依賴於許多形式不明確的行爲。這是不好的做法。之所以最終這樣做,是因爲您使用的是原始的C原始數據類型,如charint,這些數據類型指定不準確,因此很難用於位操作。

你的代碼應該被固定到安全的東西,這將使一個確定性的結果,不管系統或編譯器:

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <inttypes.h> 

int main() 
{ 
    uint8_t *buffer = malloc(sizeof(uint8_t[2])); 
    buffer[0] = 0x80; 
    buffer[1] = 0x00; 
    uint16_t address = ((uint16_t)buffer[0]<<8) | (buffer[1]); 
    printf("%" PRIu16 "\n", address); 
    free(buffer); 
    return 0; 
}