2017-07-05 59 views
5

鑑於這是法律c中數組初始化的背景是什麼?

uint8_t bytes[4] = { 1, 2, 3, 4 }; 

這是不是:

uint8_t bytes2[4]; 
bytes2 = { 1, 2, 3, 4 }; 

是什麼{ 1, 2, 3, 4 }代表什麼?

我假設它既不是右值也不是左值。一個預處理器代碼糖果,擴展到某些東西?

+6

不涉及預處理器。它只是_initialization_語法。沒有分配。 –

+0

這同樣適用於結構... – Attie

+0

一個簡單的語法 –

回答

7

{1,2,3,4}初始化列表,只能在其中陣列被聲明的線路中使用的特定語法令牌。

這純粹由C標準語法來調節。背後沒有特別的理由,這就是語言的定義。在C語法中,數組不能被賦值,也不能被賦值複製。

但是,您可以通過幾種方式躲避語法限制,一次覆蓋所有值。最簡單的方法就是創建一個臨時數組和memcpy:

uint8_t tmp[] = {5,6,7,8}; 
memcpy(bytes, tmp, sizeof bytes); 

另外,使用複合字面常量:

memcpy(bytes, (uint8_t[]){5,6,7,8}, sizeof bytes); 

如果是有道理的具體應用,你也可以包裝在陣列一個結構來繞過語法限制:

typedef struct 
{ 
    uint8_t data [4]; 
} array_t; 

... 

array_t bytes = { .data = {1,2,3,4} }; 
array_t tmp = { .data = {5,6,7,8} }; 
bytes = tmp; // works just fine, structs can be copied this way 
+0

UV'd。您可能想要添加'array_t bytes = {.data = {1,2,3,4}};','array_t bytes = {{1,2,3,4}};'和'array_t bytes = { 1,2,3,4};'都是等價的。 – chqrlie

+0

@chqrlie當然......但第一個是最明確和自我記錄。第二個是老式的C90,第三個是可疑的風格(雖然它會起作用)。許多編譯器給出了第三個版本的警告。 – Lundin

+1

您的評論是完全正確的,我不會使用第三個,因爲您提到的原因是第三個,但第二個版本的優點是可移植到不支持C99語法的環境,包括許多C++編譯器。 – chqrlie

8

句法如{1,2,3,4};被稱爲括號內含初始化列表,它是一個初始化程序。它只能用於初始化(對於數組類型)。

引用C11,章§6.7.9

  • P11

爲一個標量應是一個單一的表達的初始化,

[陣列是不一個標量類型,所以不適用於我們]

  • P14

字符類型的數組,可以用字符串文字或UTF-8字符串 文字,任選在大括號來初始化。

[我們不是使用字符串這裏的文字,所以也並不適用於美國]

  • P16

否則,初始化的對象有骨料或聯合類型應爲元素或命名成員的初始化程序列表。

[這是我們的興趣的情況下]

和,P17,

每個括號包圍的初始化列表具有相關聯的當前對象。當沒有 名稱存在,當前對象的子對象,以便根據 初始化爲當前對象的類型:在增加下標順序數組元素,結構聲明順序 構件,和一個聯合的第一個命名的構件[....]

因此,這裏,大括號括起來的列表中的值不是直接「分配」給數組,它們用於初始化數組的各個成員。

OTOH,陣列類型,是不是一個可修改的左值,所以它不能被分配。換句話說,數組變量不能用作賦值運算符的LHS。

爲了詳細說明,從C11,章§6.5.16

賦值操作員有修改的左值作爲其左操作數。

+1

到目前爲止,我一直認爲'初始化'是'聲明+賦值',它似乎不適合上面的例子。你將如何定義初始化? – TheMeaningfulEngineer

+0

@TheMeaningfulEngineer當心,他們有不同的限制。 –

+0

@TheMeaningfulEngineer我已經更新了相關的參考資料,看看是否有幫助。 –

5

初始化和分配是根本不同的事情。而對於C語言,你就必須接受這樣的事實,他們是傑出的,但當然,還有它的定義這樣一個技術原因:

在許多系統中,你可以有一個數據段在你的可執行文件文件。這部分可以被讀/寫,並給出一個初始化數組一樣

uint8_t foo[] = {1, 2, 3, 4}; // assume this has static storage duration 

編譯器可能只是直接決定輸出這個確切的字節序列到您的可執行文件。所以有沒有代碼做任務,當你的程序啓動時,數據已經存在於內存中。


OTOH,陣列不能被分配(僅其個別成員)。這就是C的定義,有時也是不幸的。

3

{1,2,3,4}是一個初始化列表。它用於指定具有至少4個元素的對象的初始值,不管它們是數組元素還是包含嵌套對象的結構成員。

不能使用這種語法將值分配給數組作爲這樣的:

bytes2 = {1,2,3,4}; 

因爲語法不被支持,並且數組不是左值。

您可以使用初始化器列表作爲被稱爲複合文字來創建對象,並把它們作爲右值的分配,返回值或函數參數C99語法的一部分:

struct quad { int x, y, z, t; }; 

struct quad p; 
p = (struct quad){1,2,3,4}; 

你仍然不能陣列使用因爲它們不是左值,但你可以實現與呼叫相同的效果memcpy()

uint8_t bytes2[4]; 
memcpy(bytes2, (uint8_t[4]){1,2,3,4}, sizeof(bytes2)); 

上述聲明乃clang編譯成一個單一的英特爾指令作爲可以在可見