[討論] 讓programmer控制variable所需的bit數?

作者: Caesar08 (Caesar)   2016-07-30 14:55:48
我很好奇,像C跟C++這種那麼底層的語言,除了部分variable(bool、float、double)
為何不全部的vairable都用、而且只能用bit-field的方式去宣告?
舉例來說
char從C++14開始的定義是至少8 bit
int的定義是至少要16 bit
如果可以改成
int:7 a;
這樣表示至少7 bit的int(然後沒有char、short、long、long long,統一用int來表示)
所以我能表示的值的範圍就從0到127,或是-64到63
如果我要寫入這個a值,那我可以寫成
a=to_unsigned(60); //存正數
a=to_signed(-30); //存負數
也就是說,a只負責存放資料,它本身不處理正負問題,讀跟寫都看programmer
func(unsigned int:6 a) //一個存放0到63的a
int *p; //pointer本身大小仍然是32或64 bit,但指向的int就不一定了
int:6 *p; //只能指向至少存放6 bit的int,如果指向int:8也可以
而且對於已經存在的compiler
如果該machine沒辦法支援這種功能,或是compiler還沒做這種功能,那
小於8的就當作8
小於16的就當作16
...
就只是把這功能關掉,其餘的跟現在的variable沒什麼不同
但如果有支援這功能,那就可以更有效地利用bit數
而且cstdint裡面的東西大概都不需要了
速度還可能可以提升?
例如現在register是32 bit,我可以讀取多個int,只要bit數加總小於或等於32就好
而不會只能讀取1或2個int(因為現在int大部分都是32 bit,但其實int指只要求16 bit)
(小弟的觀念可能有錯,這我不太確定)
不知道各位怎麼看這功能?
作者: wtchen (沒有存在感的人)   2016-07-30 15:06:00
不懂,不是已經有bit-field可以指定struct裡面的位元?真的需要自訂typedef struct不就好了?而且這樣搞法如果不能用alignment不是效能更差?
作者: CaptainH (Cannon)   2016-07-30 15:11:00
運算的時候還不是要做bit mask
作者: ilikekotomi (Young)   2016-07-30 15:49:00
只是要清楚的話 在變數命名上加bit數這樣可以更清楚
作者: MOONRAKER (㊣牛鶴鰻毛人)   2016-07-30 16:13:00
對不齊怎麼可能速度更快 噗原因就是不需要 C有那麼多user 對應那麼多硬體語言設計出來幾個常用寬度 不同實做可以各自決定這樣就很_實用_了 就算浪費空間也有限 而且方便互通你char寬度7 我寬度6 這種惡夢已經夠久了 不要再來了
作者: james732 (好人超)   2016-07-30 16:19:00
問題應該是CPU處理的效率與空間的利用?畢竟CPU指令集對於數字通常都有固定的長度?呃我不覺得這個彈性有什麼好處耶…除了複雜化以外XD
作者: CoNsTaR ((const *))   2016-07-30 17:23:00
與其讓使用者決定變數大小 還不如讓編譯器決定只要你這語言的語意可以表達得夠清楚(像fp語言)很多變數的值的上限都能在編譯期被求出來讓使用者不用擔心變數大小 真正的 bit 數編譯器會在編譯期幫你決定 你改程式也不用擔心變數大小 編譯器幫你算使用上整數就通通是 int 浮點數就全部用 double 之類的…至於無法求出上限的就照 C++ 原本標準來做 你覺得這樣如何你說的是抽象化分類的極端 我講的是泛化統整的極端這種問題沒有答案 所以…還是照原本就好囉…畢竟 C/C++ 都是強調不做太多的語言(像是沒有GC) 這種事情需要的人再用 bitfield 就好啦 XD
作者: james732 (好人超)   2016-07-30 17:26:00
整數通通是int,浮點數通通是double←這我喜歡XD我除了寫在嵌入式系統斤斤計較以外,通常都只用int...XD
作者: wtchen (沒有存在感的人)   2016-07-30 17:51:00
覺得這樣做會讓可攜性變差.... stdint原本就是為了可攜性增加的不用stdint反而各搞各的不是compiler要對應各種需求變得更複雜,就是code移到別的平台後效能差很大
作者: CoNsTaR ((const *))   2016-07-30 17:58:00
使用者輸入就是一個編譯器算不出上/下限的東西啊 這種東西照你的方法是很適合沒錯啦XD應該說是各有用途 用在不同地方吧或許你已經強制指定的編譯器就直接用你的特化版沒指定的它再幫你算 你沒指定它又算不出來看是要報錯 還是用原本標準這樣寫個程式也好累喔 XDDD 不過是滿不錯的構想啦說真的增加程式安全性
作者: wtchen (沒有存在感的人)   2016-07-30 18:04:00
是覺得這種大部份新手不會用的功能不要加進去真的必要用bit-field就好,否則debug起來又是災難
作者: CoNsTaR ((const *))   2016-07-30 18:07:00
debug 災難沒錯 不過這做法也可以避免掉很多很多 bug 了XD
作者: Sidney0503 (Sidney0503)   2016-07-30 18:28:00
你都說底層了 你知道c和組語的關係嗎........另外 C++已經可以說跟C截然不同了首先你的目的是什麼? 你想要控制值的範圍?那就是一件很奇怪的事 因為都是2^n相關你想要跑快一點 只要一次pipeline可以吃 幾bit都沒差省空間? 與其省這個不如code寫好一點基本上C往下挖就是組合語言 組合語言往下挖就是CPU硬體架構會基於軟體 軟體會被硬體牽制就算有你所謂的"未來架構" 那也會有"未來指令"有"編譯器"的理論在 就會有對應的語言
作者: wtchen (沒有存在感的人)   2016-07-30 19:22:00
在使用bit-field的時候endianness也要考慮進去
作者: netsphere (Ruby&Waku)   2016-07-30 19:22:00
type-safty表示
作者: wtchen (沒有存在感的人)   2016-07-30 19:23:00
(就可攜性來說,使用bit-field已經有點危險了)全部type都變成bit-field,考慮到endianness結果有點可怕
作者: descent (「雄辯是銀,沉默是金」)   2016-07-30 21:51:00
我現在會用 type unsigned int u32, 然後用 u32不想直接用 unsigned int 這樣的用法了最近踩一堆雷
作者: LiloHuang (十年一刻)   2016-07-30 22:49:00
樓上改用 stdint.h 的 uint32_t 呢
作者: descent (「雄辯是銀,沉默是金」)   2016-07-30 22:54:00
字太多, 打起來累人, u32, u8, u16, 你打一個我打3個
作者: LiloHuang (十年一刻)   2016-07-30 23:01:00
個人覺得 C99 標準能用則用,打字累人則是另一回事了XD
作者: wtchen (沒有存在感的人)   2016-07-30 23:11:00
為啥不typedef uint32_t u32,這樣不是安全些?
作者: yvb   2016-07-30 23:23:00
int 7:xxx; ==> union { int yyy:7 } xxx;然後再 #define xxx xxx.yyy接著 xxx = 127; ==> ok; xxx = 128; ==> warning當然若考慮 define 可能會有額外風險, 就直接用 xxx.yyy .
作者: CoNsTaR ((const *))   2016-07-30 23:29:00
可是樓上 xxx = func(); 預設是不會 warning 的 就算 func 回傳常數 128 也一樣
作者: yvb   2016-07-30 23:30:00
當然 , struct { int yyy:7 } xxx; 一樣效果.語法本身不提供 int:7 寫法, 轉個彎換寫法效果一樣.當然, 其中的 int yyy:7 和 long long yyy:7 應該會相同;但寫 char yyy:7 或 short yyy:7 會不同(前提用 32 bit 機器)上兩句可能和機器及編譯器,甚至編譯選項相關, 請忽略.回 CoNsTaR: 只是驗證是有 int:7 效果, 設128去印應該會是0.
作者: kevingwn (如雲如風的人生)   2016-07-30 23:52:00
省空間是說想要vector<int6_t>這樣的操作嗎?應該是辦得到,但效能應該比vector<int8_t>差很多通常只有在存成檔案或網路傳輸等會有這樣的需求吧?
作者: TobyH4cker (Toby (我要當好人))   2016-07-31 00:02:00
看來沒寫過組語哦,看懂了,不過我覺得指明跟不指明沒差,因為本來就是要看文件,把文件的規範讀的很精熟的話,coding起來比較容易至於你說那些新手,或是老手都還不知道實際大小那些,只是表面他們學得不夠或看得不夠而已但是你的想法其實可以帶來一個好處,就是整數型態就只要有int跟uint就夠了,手動指定最小bit數,compiler來安排它要用多大空間這樣,吧?嗯嗯那signed跟unsigned你會怎麼做0.0
作者: wtchen (沒有存在感的人)   2016-07-31 16:20:00
還有一個問題,怎麼判斷是否overflow?這樣搞的話要弄一個header把所有可能的max/min define進去
作者: CoNsTaR ((const *))   2016-07-31 17:05:00
樓上這麼做的優點就是不用考慮 overflow 啊…你已經知道它在這個程式裡有可能被賦的最大最小值了 怎麼會 overflow我也認同原 po sint int uint 的構想只是我覺得 signed unsigned (原本是 modifier) 可以變成像是 const 那樣的東西(qualifier)int (specifier) 本身可以儲存任何整數 但是一旦加了 signed/unsigned你就不能賦 正/負 數給他就像加 const 一樣,你就不能賦 non-const 給他這麼做 int 的本質不會改變 但是編譯器會為你做額外的檢查,保證你沒有把不對的值賦給變數這樣的好處是,這三種型態實際上是一模一樣的,只是你給他們一些限制所以 int 裝得下的數字其他兩種一定也裝得下(不會 overflow,cast 的時候 binary 值也不會改變)至於 casting 規則嘛……
作者: wtchen (沒有存在感的人)   2016-07-31 18:17:00
原創的使用者可以自訂範圍,只是如果多人一起編輯恐怕會加深code的複雜度....
作者: CoNsTaR ((const *))   2016-07-31 18:20:00
w大 不太懂你的問題耶…
作者: wtchen (沒有存在感的人)   2016-07-31 18:29:00
<= 16 bit好解決,如果是> 16 bit 那還要記不同bit的最大最小值? (我算術不好不能一眼看出來)除非一直用2進位或16進位,如果要轉到10進位就....至於bit field vs. endianness 可以看這裡:http://mjfrazer.org/mjfrazer/bitfields/
作者: CoNsTaR ((const *))   2016-07-31 19:01:00
喔喔 其實沒有那麼複雜啊 因為只有某些特殊值的上下限是需要你手動定義的 像是 協定裡某個值的上下限/輸入輸出能接受的上下限 之類 剩下的其實都可以在編譯時期動態的決定
作者: kevingwn (如雲如風的人生)   2016-07-31 21:26:00
用struct去包不會麻煩呀 http://ideone.com/EF6eUs倒是覺得vector<int4_t>比較困難
作者: Sidney0503 (Sidney0503)   2016-07-31 21:58:00
說真的我不懂你的需求光你說擺再一起省空間 很想叫你去念計算機組織首先 管bit不是在管硬碟block 光是紀錄就要消耗多少多少空間 其次先不談對齊問題你要如何設計一個CPU可以同時執行兩個指令?pipeline一次就是吃這麼多bit 你空下來又如何?我覺得你拿去八卦版問比較好 人比較多 也不只C說不定精通其他語言的人會幫你解答
作者: CoNsTaR ((const *))   2016-07-31 22:36:00
樓上重點錯誤吧……
作者: yoco (眠月)   2016-07-31 22:39:00
我覺得不是不行,只是沒有人寫 proposal 給標準委員會你寫一份吧就像 C++11 沒有 VAL,不是不行,單純只是沒人提 proposal
作者: wtchen (沒有存在感的人)   2016-07-31 22:52:00
Sidney0503講的是Write amplification嗎?
作者: Sidney0503 (Sidney0503)   2016-08-01 06:48:00
樓上說的是我其中一個想法 我真的想不到如何省空間..你現在又跟我說表示值的範圍 我最一開始就說很奇怪為甚麼值的範圍只能是2^n次方 根本就不符合使用除了bool 大多數我們使用的數字範圍都不是2^n天堂32767和戰神65535一看就知道是被硬體牽制而不是使用需求才設這個範圍這種邊界的問題生出物件的原則像JAVA慣用set和get原來你知道什麼叫硬體不好設計阿 我還以為你不知道耶我已經跟你說了就是慣用的set和get會限制邊界難不成我用你的API還要看每個變數的範圍?
作者: wtchen (沒有存在感的人)   2016-08-01 17:21:00
以後量子電腦如果成功量產,1 bit 就能表示成0~7搞不好C standard也要全部重新定義
作者: chchwy (mat)   2016-08-01 18:11:00
就CPU的角度來說 你的建議完全不會增加效能
作者: goliathplus (No Comment)   2016-08-05 00:02:00
因為沒有意義阿 硬體架構要 ALIGN 單一變數指定bit沒有顯著優點阿
作者: tomjpsun (湯姆熊)   2016-08-05 17:09:00
RAM 越來越大碗,連 embedded system 也有受惠, 所以十年前是應該考慮這些,但是現在其實容易 maintain 可能比較重要吧!
作者: jeff04209 (yo)   2016-08-12 18:55:00
你cache怎麼放?memory 怎麼放?拿資料一次要拿多少?你處理器每次拿資料都要用額外的邏輯去判斷,這個複雜度...你以為你高階語言想怎麼寫就怎麼寫喔,硬體為了這點沒什麼幫助的功能所耗的cost有多大你知道嗎
作者: jun0325 (俊)   2016-08-17 01:10:00
硬體沒有難不難做...只是要看compiler和硬體要如何合作罷了。就算你新增了bit field的語意,要讓它跑在原本的CPU也是可以,就只是讓compiler增加原本的工作去support你要的語意,用原本的ISA去拼出你想要的functionality,反之亦然,可以extend ISA減少compiler的工作。不過要讓不同長度的變數pack到同一個register裡,你要讓硬體如何對其中一個變數做運算XD。我能想到最接近的概念就是SSE了。可以參考這http://goo.gl/ahdejN讓你對register packing會比較有概念
作者: Sidney0503 (Sidney0503)   2016-08-24 08:43:00
那是struct 每一次使用就是會要一整個區塊空間就算你變數真的用bit field 也是每次要一個變數的空間不會省空間struct大太 就是倍數整區塊怕你不懂 假設八位元 struct要到的空間就是總 bit數/8 取天花板 *8 ok?打包一群變數 可以靠命命開頭讓人知道是同群組資料struct是連硬體位置都連在一起只能說你對c/組合語言/計算機架構完全沒概念在你好好念書之前 你永遠都無法理解你的14+2=16bit是多外行的說法而硬體連續性也是陣列最重要的 因為struct把變數的空間連續 陣列才能取用struct裡面的面數用命名開頭表示群組 會被compiler打散 效能自然差比起在這邊跟板友筆戰 不如先好好念底層的原理
作者: EdisonX (卡卡獸)   2016-08-25 23:11:00
亂入一下,C++ 是建議變數用到時才宣告,所以是建議第一種

Links booklink

Contact Us: admin [ a t ] ucptt.com