2013-10-27 116 views
0

我在我有一個全球性陣列指向全局靜態變量的指針 - 不安全?

static char name[6]; 

和功能

static char* gen_name(char* dest, const size_t len) { 
    for (int i = 0; i < len - 1; ++i) 
     dest[i] = 'A' + (genrand_uint32() % ('Z' - 'A')); 
    dest[len - 1] = '\0'; 
    return dest; 
} 

的指針的名稱然後被存儲在不同的頭文件中的全局變量文件,這個變量不靜態的。

this_name = gen_name(name, sizeof name); 

在另一個文件中的函數使用這個指針,它的工作原理以及在Linux上,但是當我在微控制器上運行相同的代碼,它打印亂碼。 當我刪除static關鍵字時,它工作正常。

這是怎麼發生的?

什麼時候應該使用static? 我以爲我應該聲明所有變量和函數不在文件外部使用爲static,這是錯誤的嗎?

+0

顯示變量'name'填入的代碼。 – abelenky

+0

'static char * gen_name(...)'不會做你認爲它的作用。 –

+0

@RaymondChen如何? (注意:'for'頭後的第二行縮進令人困惑,但不影響編譯器看到它的方式。) –

回答

1

當您在標題中聲明變量時,是否記得標記它extern?你需要這樣做,否則會發生的是,你只是在包含頭文件的每個文件中得到一個新變量。請記住,#include只是一個副本&粘貼作業;預處理器只是將頭文件中的文本插入包含發生的位置。如果頭文件中的文本是char name[6],那麼這就是你所得到的;源代碼中的文字爲char name[6],導致變量name與您其他源文件中的變量無關。

如果您將其標記爲extern,則鏈接器將會抱怨找不到符號。這意味着name的定義不能爲static,因爲這會導致鏈接器無法找到它。

所以,在你的頭文件,你需要這樣的聲明:

extern char name[6]; 

,並在源文件中,你需要這樣的定義:

char name[6]; 

並回答實際的問題:是的,它非常安全。

+0

謝謝,我不知道'extern'部分,現在我有一個帶'extern char * this_name;'的頭文件,帶有'char * this_name的相應.c文件'和從頭開頭的.c文件,帶有'static char name [6];',名稱的實際內存位置。但是,當我聲明靜態名稱時,'this_name'會打印垃圾,而當我不使用'static'時則不會。 – user1273684

+0

如果您只需幾行代碼即可生成最小程序,但仍會出現問題,這將有所幫助。因爲現在,它可能是你的代碼中的其他任何東西都會混淆「name」的內容。 –

0

原來,它是由不同線程中的堆棧溢出引起的,標記爲靜態會將其放在bss節中,位於堆棧後面,這會溢出。

-1

靜態關鍵字對函數和變量意味着不同的東西。

函數默認爲'extern',即它們的入口點由編譯器公開,所以鏈接器可以找到它們,並且可以從任何編譯模塊中調用它們。 如果你把'static'放在函數聲明的前面,這個函數將停止被公開,即它只會在同一個源模塊中被知道。

'static'關鍵字在用於變量(*)時具有非常不同的含義。這使得它們不可更改。 當你說'靜態字符名稱[6]'時,你告訴編譯器你無意改變'name'的值。

在運行在PC上的Linux上,這並不意味着太多。你告訴編譯器你不會改變這個值,然後你改變它。你撒謊。沒什麼大不了。

一些微控制器具有內部閃存,可以用它們來運行代碼並保持固定(恆定!)數據。 編譯器和鏈接器使用您的承諾,即'name'不會更改,並將變量保留在閃存中記憶。 你可以想象當你嘗試改變它時會發生什麼(不)。

更確切地說,編譯器會將所有的靜態變量置於.const段,然後鏈接器將該段放入閃存中。

(*)有一種方法可以查看'const',使它在用於變量時具有與函數相同的含義。這裏不重要。