[英]statically allocated variable when using getpwnam()
我正在研究系統編程。
有很多函數返回靜態分配的變量。
其中之一是getpwnam()
。
因此,在本書示例中,我正在閱讀:
printf("%ld %ld\\n", (long)(getpwnam("tsr")->pw_uid), (long)(getpwnam("avr")->pw_uid));
兩者都返回相同的uid,盡管在/etc/passwd
,它們的uid不同。 並且,解釋原因。
這是問題。
但是,我認為這是由於靜態分配的變量。 但是,結果是輸出是不同的(例如,類似於3001、3005)。
為什么輸出不同?
根據這本書,輸出應該是相同的。
並且,是否在函數中返回靜態分配的變量(如局部變量(自動變量))?
例如:
char* func(const char** name)
{
char str[256];
strcpy(str,name);
return str;
}
編譯器可以自由調用getpwname
,然后以其喜歡的任何順序訪問pw_uid
字段。
例如,它可能生成如下代碼:
struct passwd *pw1 = getpwname("tsr");
struct passwd *pw2 = getpwname("avr");
long uid1 = pw1->pw_uid;
long uid2 = pw2->pw_uid;
printf("%ld %ld\n", uid1, uid2);
它將打印相同的數字,因為對getpwname
兩次調用getpwname
返回指向相同static
變量的指針,而第二個調用將getpwname
一個指針編寫的內容,然后我們才有機會獲取所需的數據。 這是本書所期望的事情。
另一方面,編譯器也可能會選擇執行類似
struct passwd *pw1 = getpwname("tsr");
long uid1 = pw1->pw_uid;
struct passwd *pw2 = getpwname("avr");
long uid2 = pw2->pw_uid;
printf("%ld %ld\n", uid1, uid2);
在這種情況下,我們需要的信息(UID)在第二次調用getpwname
之前被保存在另一個變量中。
需要強調的是,兩種生成代碼的方式都對編譯器合法(從技術上講,函數的參數之間沒有序列點,因此副作用可能以任何順序發生),因此您應像在第二個示例,以確保它將始終正常運行。
(順便說一句,通常最好通過支持這些函數的可重入版本來避免這些意外情況-例如, getpwnam_r
不會返回指向在下一次調用時被覆蓋的靜態數據的指針,而是填充您提供的結構)
並且,是否在函數中返回靜態分配的變量(如局部變量(自動變量))?
不完全是; 返回指向局部變量的指針是非法的,因為當函數返回時,該變量“在邏輯上不復存在”,因此,您將返回一個不再擁有的內存的指針; 實際上,無論何時重用其在堆棧中的位置(例如,在下一個函數調用時或在函數的后面),此類內存都會被不相關的數據意外地覆蓋。
相反,返回指向靜態分配的變量的指針(即,全局或static
局部變量-實際上實際上是一個偽裝的全局變量)是合法的-該內存是您的,並且不會隨處可見-但由於該內存在對該調用的所有調用之間共享函數,勢必在下一次調用該函數時被覆蓋。 這使得編寫在嵌套調用中使用該功能的代碼變得復雜,並且線程安全或異步安全(如:在信號處理程序中可用)的代碼完全不可能。
根據文檔, getpwnam
返回指向靜態存儲的指針,隨后的對getpwent
, getpwnam
或getpwuid
調用可能會覆蓋它。 這就是為什么您看到不一致的結果。 作為建議,您可以使用這些函數的reentrent變體getpwnam_r
和getpwuid_r
,將信息返回給用戶提供的緩沖區,而不是靜態緩沖區。
並且,是否在函數中返回靜態分配的變量(如局部變量(自動變量))?
不同之處在於,靜態存儲的數據只初始化一次並存在於程序的整個生命周期中,而這些自動變量僅存在於定義的塊中。 因此,在您的示例中,當函數func
返回時, str
數組不再存在,並且使用它是未定義的行為。 如果是靜態的,則可以。
char* func(const char** name)
{
static char str[256];
strcpy(str,name);
return str;
}
但是請記住,使用靜態數據通常會導致該函數無法重入。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.