2017-07-25 115 views
-1

我有一個函數打印字符數組的內容:是否將char *轉換爲int * undefined?

#include <stdio.h> 

void print_array(char * array, int n) { 
    char* start; 

    for(start = array; start - array < n && printf("%d\n", *start); start++); 
} 

int main() { 
    char array[5] = {'a', 'b', 'c', 'd', 'e' }; 
    print_array(array, 5); 

    return 0; 
} 

這個工程很好地進行打印:

void print_array(int * array, int n) { 
    int* start; 

    for(start = array; start - array < n && printf("%d\n", *start); start++); 
} 
:如果我改變功能這一

97 
98 
99 
100 
101 

麻煩的開始

然後調用如下函數:

print_array((int*)array, 5); 

這會打印垃圾。

1684234849 
101 
1973473280 
8388443 
80884992 

編譯時我打開了-Wall,它沒有引發警告。爲什麼當我改變指針時我會變得垃圾?

+2

是的,它是未定義的。其他問題?請注意,您還在界限之外打印以及其他所有類似內容。 –

+0

@AnttiHaapala是的。爲什麼沒有 - 會發出警告? –

+0

這是C.這是設計讓你自己在腳下射擊的語言。在這裏,你故意將槍指向你的腳並拉動扳機,所以編譯器會假設你知道你在做什麼。 –

回答

2

正如別人指出的,你的第二個實現是undefined

正如其他人所說,由於您將數組的地址從(char *)轉換爲(int *),因此編譯器假定您知道自己在做什麼並且不會發出警告。嘗試編譯沒有演員看到你的警告。

現在,給你是怎麼回事的架構具體例子(注:這個例子還是未定義),想想看:

假設機體系結構採用了炭1個字節和4個字節INT ...

在您的代碼:

char array[5] = {'a', 'b', 'c', 'd', 'e' }; 

您分配的5字符的數組。他們可能看起來像這樣的記憶:

0x61 0x62 0x63 0x64 0x65 

然後調用

print_array(array, 5); 

在這種用法和語境,陣列實際上是一個隱含的指針&數組[0],這是(char *)並指向0x61。

現在在函數調用中,您將數組轉換爲(int *)。你所擁有的是一個由5個元素組成的數組,每個元素的寬度爲1個字節,現在被解釋爲(仍然)5個元素的數組,每個元素... 4個字節寬!這可能看起來像這樣在內存中:

0x61626364 0x65?????? 0x???????? 0x???????? 0x???????? 

您的(int *)實現中只需要5個字節定義所需的20個字節。

根據您的機器的字節序的第一個INT可以被解釋爲

  • 1684234849(小端 - 看你上面的結果)
  • 1633837924(大端)

你已經注意到打印時的其他4個元素是垃圾,因爲我們不知道內存的內容。

還要注意,你在第二個「int」元素上溢出了你的char [5]數組。

再次,這個例子是架構相關的,並且undefined。你可能在另一個架構上有完全不同的行爲。

編輯: 它看起來像一個偶然的機會,你的第二個「INT」是

0x65000000 

而且在小尾數解釋:101,就像您在輸出中看到。

但這是運氣。它可能是垃圾。

6

int*const char*的轉換是明確的。

反過來也是如此,如果基礎數據是int[]數組,但你不能在一個陣列由const char*指向一個int*轉換任意點指出:你可能不尊重對齊要求。

因此,您的行爲是undefined,因爲您從char數組開始。

+0

從'int *'到'char *'的轉換是否已定義良好?有什麼特別的理由說明你的const char *類型轉換? – SebNag

+1

@SebNag:絕對!它**必須**是一個'const char *'。 – Bathsheba

+1

不尊重對齊要求只是一件事,打破嚴格的別名是第二,第三(大多是現今正常計算機上的假設)將是'int'中的陷阱值。 –