[英]Can a char array be used with any data type?
malloc()
函數返回一個void*
類型的指針。 它根據作為參數傳遞給它的size_t
值以字節為單位分配內存。 生成的分配是原始字節,可以與C中的任何數據類型一起使用(無需轉換)。
可以在返回void *
的函數中聲明類型為char
的數組,可以與任何數據類型一起使用,例如生成的malloc
分配嗎?
例如,
#include <stdio.h>
void *Stat_Mem();
int main(void)
{
//size : 10 * sizeof(int)
int buf[] = { 1,2,3,4,5,6,7,8,9,10 };
int *p = Stat_Mem();
memcpy(p, buf, sizeof(buf));
for (int n = 0; n < 10; n++) {
printf("%d ", p[n]);
}
putchar('\n');
return 0;
}
void *Stat_Mem()
{
static char Array[128];
return Array;
}
靜態對象Array
的聲明類型是char
。 該對象的有效類型是它的聲明類型。 無法更改靜態對象的有效類型,因此對於程序的其余部分, Array
的有效類型為char
。
如果嘗試訪問具有與此列表1不兼容或不相關的類型的對象的值,則行為未定義。
您的代碼嘗試使用int
類型訪問Array
的存儲值。 此類型與char
類型不兼容,並且不在異常列表中,因此當您使用int
指針p
讀取數組時,行為是未定義的:
printf("%d ", p[n]);
1 (引用自:ISO:IEC 9899:201X 6.5表達式7)
對象的存儲值只能由具有以下類型之一的左值表達式訪問:
- 與對象的有效類型兼容的類型,
- 與對象的有效類型兼容的類型的限定版本,
- 對應於對象的有效類型的有符號或無符號類型的類型,
- 對應於對象有效類型的限定版本的有符號或無符號類型,
- 聚合或聯合類型,其成員中包含上述類型之一(包括遞歸地,子聚合或包含聯合的成員),或者
- 角色類型。
不可以因為可能的對齊問題而無法將任意字節數組用於任意類型。 標准在6.3.2.3轉換/指針(強調我的)中說:
指向對象或不完整類型的指針可以轉換為指向不同對象或不完整類型的指針。 如果生成的指針未針對指向類型正確對齊,則行為未定義 。 否則,當再次轉換回來時,結果將等於原始指針。
作為最小對齊要求的char,您無法確保您的char數組將正確對齊任何其他類型。 這就是為什么malloc保證malloc獲得的緩沖區(即使它是一個void *
)具有最大可能的對齊要求,以便能夠接受任何其他類型。
我覺得
union {
char buf[128];
long long i;
void * p;
long double f;
};
應該對任何類型都有正確的對齊方式,因為它與最大的基本類型兼容(如6.2.5類型中所定義)。 我很確定它適用於所有常見的實現(gcc,clang,msvc,...)但遺憾的是我無法找到標准允許的任何確認。 基本上是因為6.5表達式§7中定義的嚴格別名規則:
對象的存儲值只能由具有以下類型之一的左值表達式訪問:
- 與對象的有效類型兼容的類型,
- 與對象的有效類型兼容的類型的限定版本,
- 與對象的有效類型對應的有符號或無符號類型的類型,
- 與有效類型的對象的限定版本對應的有符號或無符號類型的類型,
- 聚合或聯合類型,包括其成員中的上述類型之一(包括遞歸地,子聚合或包含聯合的成員),或者
- 一個字符類型。
所以恕我直言,沒有可移植和標准符合方式來構建不使用malloc
的自定義分配器 。
如果讀取C89標准的基本原理,存在類型別名規則的唯一原因是避免要求編譯器做出“最壞情況的混疊假設”。 給出的例子是:
int a;
void f( double * b )
{
a = 1;
*b = 2.0;
g(a);
}
如果程序在一個聯合內創建一個“char”數組,其中包含一些對齊適合任何類型的東西,獲取其地址,並且永遠不會訪問該結構的存儲,除非通過結果指針,否則應該沒有理由應該使用別名規則造成任何困難。
值得注意的是,標准的作者認識到實施可以同時兼容但無用; 見C89 2.2.4.1的基本原理:
雖然有缺陷的實施可能會設計出滿足這一要求的計划,但仍然沒有成功,委員會認為這種聰明才智可能需要更多的工作而不是做一些有用的工作。 委員會的意義在於,實施者不應將翻譯限制解釋為硬連線參數的值,而應將其作為判斷實施的一套標准。
雖然該特定聲明是關於實施限制的,但將C89解釋為與之前的C語言甚至遠程兼容的唯一方法是將其視為更廣泛地應用:標准並未試圖詳盡地指定程序應該能夠做的所有事情,但依賴於編譯器編寫者的一些常識。
使用字符類型數組作為任何類型的后備存儲,假設一個確保對齊問題得到處理,不應該導致非編寫的非編譯器的任何問題。 標准沒有要求編譯器編寫者允許這樣的事情,因為他們認為沒有理由期望他們這樣做。 不幸的是,他們未能預見到21世紀語言的發展方向。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.