[閒聊] 為什麼 C 語言不提供指向虛無的指標
看板C_and_CPP (C/C++)作者Hazukashiine (みなさん、こんにちは)時間7年前 (2017/10/10 13:28)推噓24(24推 0噓 73→)留言97則, 21人參與討論串1/1
在 C 語言裡面對 NULL 取值是非法的
通常伴隨的是發生 segmentation fault
而這通常也跟 CPU 的指令集實作有關
因為編譯器會將對 NULL 取值的程式碼
假定 NULL 就是常數數值 0 的情況下
編譯成類似 movl $10, 0x0 等的指令
因此 CPU 在處理相關指令的時候
豎立 flag 觸發 OS 處理是可以預期的
但是既然 C 語言被定調成高階語言
為什麼不提供一些抽象一些的語意
像是對「虛無指針」取值是代表忽略的意思
比如說 VACANT 代表「虛無指針」
則 void *arr[] = {VACANT, VACANT};
*arr[1] = (uintptr_t)12345;
代表什麼事(包含副作用)都不會發生
感覺對空虛取值不發生作用非常實用
就像指令集幾乎都會有 NOP 一樣
表面上看起來沒什麼用
但是卻能在不少 corner cases 發生作用
NOP 可以去解決 hazard 的問題
VACANT 可以解決不少指針初始化的問題
可以減少程式設計所需的 sentinel value
還在特定的時候能讓程式減少無謂的判斷式
基本上我還沒想到什麼負面的影響
我的問題是為什麼不設計類似的指針?
類似 /dev/null 的概念
看起來沒什麼用 但是卻大大有用 XD
--
作者 sr29 (owo) 看板 Linux
標題 [問題] git add 失敗
時間 Wed Jul 12 15:31:13 2017
→
07/12 15:52,
07/12 15:52
→
07/12 15:53,
07/12 15:53
推
07/13 04:41,
07/13 04:41
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 122.116.185.23
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1507613289.A.22D.html
推
10/10 13:38,
7年前
, 1F
10/10 13:38, 1F
推
10/10 13:45,
7年前
, 2F
10/10 13:45, 2F
→
10/10 13:45,
7年前
, 3F
10/10 13:45, 3F
→
10/10 13:45,
7年前
, 4F
10/10 13:45, 4F
就跟 NULL 一樣 型態都是 void* 只是一種特殊指標
1. void *ptr = VACANT;
*ptr = dont_care; // 沒事發生
或是說
2. void val = "i don't care"; // 一樣沒事
也就是說對 void 賦值是無反應的 www
但是如果是
3. void *ptr = NULL;
*ptr = "segfault" // 錯誤發生
這個就是按照 lagacy 的做法
→
10/10 13:47,
7年前
, 5F
10/10 13:47, 5F
C++ 太複雜惹
推
10/10 13:53,
7年前
, 6F
10/10 13:53, 6F
→
10/10 13:55,
7年前
, 7F
10/10 13:55, 7F
這個應該就真的比較複雜了
假定編譯器頭文件是這樣實作的
#define VACANT ((void*)(0xFFFFFFFFFFFFFFF))
也就是要從 CPU 設計變更下手
只要對存取最後一個保留地址當作沒反應的指令
就像 NOP 一樣 這樣也許可行吧(?
推
10/10 14:06,
7年前
, 8F
10/10 14:06, 8F
→
10/10 14:06,
7年前
, 9F
10/10 14:06, 9F
二樓的那個問題在於「把 void 型態賦值到 int」
如果改成 int x = *(uintptr_t*)VACANT; 的話...
答案大概就是... x = 0xFFFFFFFF 吧(從 64bit 變成 int: 32bit 截斷)
→
10/10 14:07,
7年前
, 10F
10/10 14:07, 10F
→
10/10 14:08,
7年前
, 11F
10/10 14:08, 11F
*(int*)VACANT = (int)5487; 的話應該比較簡單
畢竟 VACANT 代表的就是最後的保留地址的數值,那轉型再取值應該就還是沒反應吧
應該是這麼說 VACANT 的數值也是機器依賴的
編譯器要端看 CPU 是怎麼實作的
以假設對 CPU 來說地址第 8~15 位元組用作忽略地址的話
那麼 #define VACANT ((void*)(0x8)) 才是正確的
不過這在 CPU 解碼前期就要多一個小電路
讓該送進來指令變成氣泡或是直接讓下一個指令直接遞補上
這樣其實也不會太難
只要 63 個 OR gates 和 1~2 個 NOT gate 去當 mux 的 select
看是是不是要觸發 instruction queue 的遞補(?
推
10/10 14:23,
7年前
, 12F
10/10 14:23, 12F
好問題 @@
如果是
int *ptr = VACANT;
printf("%d\n", *ptr);
的話呢...
應該還是 segfault 跟 NULL 一樣
我覺得應該是這樣
畢竟 VACANT 的地址不在程序的可以讀的權限裡
但是所有的程序對那個地址都有寫入的權限
跟 /dev/null 一樣 只要讀就是直接拿到一個 EOF
推
10/10 14:25,
7年前
, 13F
10/10 14:25, 13F
→
10/10 14:26,
7年前
, 14F
10/10 14:26, 14F
→
10/10 14:26,
7年前
, 15F
10/10 14:26, 15F
推
10/10 14:27,
7年前
, 16F
10/10 14:27, 16F
→
10/10 14:27,
7年前
, 17F
10/10 14:27, 17F
→
10/10 14:27,
7年前
, 18F
10/10 14:27, 18F
→
10/10 14:27,
7年前
, 19F
10/10 14:27, 19F
→
10/10 14:27,
7年前
, 20F
10/10 14:27, 20F
→
10/10 14:27,
7年前
, 21F
10/10 14:27, 21F
→
10/10 14:27,
7年前
, 22F
10/10 14:27, 22F
→
10/10 14:27,
7年前
, 23F
10/10 14:27, 23F
→
10/10 14:27,
7年前
, 24F
10/10 14:27, 24F
→
10/10 14:27,
7年前
, 25F
10/10 14:27, 25F
沒錯 正因為如此
所以才用 preprocessor macro
指定一個機器相依的數值
編譯器不需要知道 void* 型態的變數是不是裝 VACANT
因為 VACANT 就是一個定值
當語言被編譯成執行檔的時候
會變成 movl $10, 0x8
當機器要執行這行指令的時候
就會直接把 10th register 的值直接丟掉
讀取的時候也會
因為程序沒有這段地址的讀取權限產生 segfault
推
10/10 14:32,
7年前
, 26F
10/10 14:32, 26F
→
10/10 14:32,
7年前
, 27F
10/10 14:32, 27F
推
10/10 15:50,
7年前
, 28F
10/10 15:50, 28F
還有 31 則推文
還有 11 段內文
這是個好問題
我要操作這個 queue 超過 10兆 次以上
但是 prefill 這個 queue 也不過 64 個 elements
幾乎是微乎其微 兩權相害取其輕 XD
推
10/11 02:15,
7年前
, 60F
10/11 02:15, 60F
→
10/11 02:15,
7年前
, 61F
10/11 02:15, 61F
→
10/11 02:15,
7年前
, 62F
10/11 02:15, 62F
→
10/11 03:00,
7年前
, 63F
10/11 03:00, 63F
→
10/11 03:00,
7年前
, 64F
10/11 03:00, 64F
→
10/11 03:03,
7年前
, 65F
10/11 03:03, 65F
→
10/11 03:22,
7年前
, 66F
10/11 03:22, 66F
→
10/11 03:23,
7年前
, 67F
10/11 03:23, 67F
→
10/11 03:23,
7年前
, 68F
10/11 03:23, 68F
→
10/11 03:24,
7年前
, 69F
10/11 03:24, 69F
→
10/11 03:25,
7年前
, 70F
10/11 03:25, 70F
→
10/11 03:26,
7年前
, 71F
10/11 03:26, 71F
→
10/11 03:26,
7年前
, 72F
10/11 03:26, 72F
→
10/11 03:26,
7年前
, 73F
10/11 03:26, 73F
→
10/11 03:28,
7年前
, 74F
10/11 03:28, 74F
→
10/11 03:28,
7年前
, 75F
10/11 03:28, 75F
推
10/11 13:00,
7年前
, 76F
10/11 13:00, 76F
推
10/11 17:10,
7年前
, 77F
10/11 17:10, 77F
→
10/12 15:36,
7年前
, 78F
10/12 15:36, 78F
→
10/12 15:38,
7年前
, 79F
10/12 15:38, 79F
→
10/12 15:38,
7年前
, 80F
10/12 15:38, 80F
→
10/14 02:12,
7年前
, 81F
10/14 02:12, 81F
→
10/14 02:12,
7年前
, 82F
10/14 02:12, 82F
→
10/14 02:13,
7年前
, 83F
10/14 02:13, 83F
→
10/14 02:14,
7年前
, 84F
10/14 02:14, 84F
→
10/14 02:14,
7年前
, 85F
10/14 02:14, 85F
※ 編輯: Hazukashiine (122.116.185.23), 10/14/2017 11:40:43
推
10/14 21:55,
7年前
, 86F
10/14 21:55, 86F
→
10/14 21:56,
7年前
, 87F
10/14 21:56, 87F
→
10/14 21:56,
7年前
, 88F
10/14 21:56, 88F
→
10/14 21:58,
7年前
, 89F
10/14 21:58, 89F
→
10/14 21:58,
7年前
, 90F
10/14 21:58, 90F
→
10/15 00:41,
7年前
, 91F
10/15 00:41, 91F
推
10/15 06:47,
7年前
, 92F
10/15 06:47, 92F
→
10/15 11:25,
7年前
, 93F
10/15 11:25, 93F
→
10/15 11:26,
7年前
, 94F
10/15 11:26, 94F
→
10/15 11:27,
7年前
, 95F
10/15 11:27, 95F
→
10/15 11:28,
7年前
, 96F
10/15 11:28, 96F
→
10/15 11:28,
7年前
, 97F
10/15 11:28, 97F
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章