下面的程式編譯沒有錯誤。
#include <stdio.h>
char addr_a[8];
char addr_b[8];
unsigned long my_addr = (unsigned long)addr_a 8; // PASS
// unsigned long my_addr = (unsigned long)addr_a (unsigned long)addr_b; // FAIL (error: initializer element is not constant)
int main() {
printf("%lx\n", my_addr);
return 0;
}
有趣的是,當我設定unsigned long my_addr = (unsigned long)addr_a (unsigned long)addr_b編譯器時拋出“錯誤:初始化元素不是常量”。
我知道全域變數只能用常量運算式初始化。我還知道可以在全域初始化程式中使用的常量運算式的型別在C 標準的第 6.6p7 節中指定:
初始值設定項中的常量運算式允許有更多的自由度。此類常量運算式應為或評估為以下之一:
- 一個算術常量運算式,
- 空指標常量,
- 地址常量,或
- 完整物件型別的地址常量加上或減去整數常量運算式。
請注意,允許地址常量加整數常量,但不允許地址常量加另一個地址常量。
題:
為什么 C 標準限制了初始化全域變數的方式?是什么阻止了 C 標準的接受unsigned long my_addr = (unsigned long)addr_a (unsigned long)addr_b?
uj5u.com熱心網友回復:
具有靜態存盤持續時間的物件(即全域變數,加上定義為 的區域變數static)只能用常量運算式初始化。
在C 標準的第 6.6p7 節中指定了可以在此類物件的初始化程式中使用的常量運算式型別:
初始值設定項中的常量運算式允許有更多的自由度。此類常量運算式應為或評估為以下之一:
- 一個算術常量運算式,
- 空指標常量,
- 地址常量,或
- 完整物件型別的地址常量加上或減去整數常量運算式。
請注意,允許地址常量加整數常量,但不允許地址常量加另一個地址常量。
誠然,這仍然是不正是你所擁有的,因為你必須強制轉換為整型常量地址。因此,讓我們檢查 6.6p6,它定義了一個整數常量運算式:
一個整數常量運算式應具有整數型和應僅具有是積分常數,列舉常數,字符常數,sizeof運算式其結果是積分常數,運算元
_Alignof的運算式,和浮動常量是鑄件的立即運算元。整數常量運算式中的強制轉換運算子只能將算術型別轉換為整數型別,除非作為sizeofor_Alignof運算子的運算元的一部分 。
本段不允許將地址常量轉換為整數型別作為整數常量運算式的一部分,但顯然這似乎被支持作為擴展。
uj5u.com熱心網友回復:
是什么阻止了 C 標準接受 unsigned long my_addr = (unsigned long)addr_a (unsigned long)addr_b?
根本原因是“因為為什么會有人想要那個?” 兩個絕對地址相加沒有意義;結果不是任何特別的地址。
因此,這是一種先有雞還是先有蛋的事情。該語言不支持它,因為它沒用,還因為現有的聯結器和目標檔案格式不支持這種重定位。例如,對于 x86-64 上的 ELF,請參閱psABI表 4.9 以獲取支持的重定位串列,并注意沒有S S. 聯結器不支持它,因為它沒用,并且因為語言不需要支持它。
我猜最初,這些工具可能出現在語言之前(最早的 C 編譯器會使用為匯編程式設計的聯結器)。所以最初的工具可能不支持這一點,語言認為沒有必要要求他們這樣做,隨著時間的推移,沒有人認為需要添加它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/366412.html
上一篇:列印C陣列時的垃圾
