cbrt c语音_C语言有哪些鲜为人知的特性?
本文由?伯樂在線?-?Lingfeng Ai?翻譯自?Quora。未經許可,禁止轉載!
歡迎加入:技術翻譯小組,或分享原創到伯樂頭條。
譯注:本文摘編自 Quora 的一個熱門問答貼。 請在linux系統下測試本文中出現的代碼
switch語句中的case?關鍵詞可以放在if-else或者是循環當中
1. 聲明緊隨用途之后
理解聲明有一條很簡單的法則,不過不是什么“從左向右”這種沒道理卻到處宣傳的法則。這一法則的觀點是,一個聲明是要告訴你,你所聲明的對象要如何使用。例如:
2. 指定初始化:
在C99之前,你只能按順序初始化一個結構體。在C99中你可以這樣做:
這段代碼首先初始化了foo.z,然后初始化了foo.x.?foo.y?沒有被初始化,所以被置為0。
這一語法同樣可以被用在數組中。以下三行代碼是等價的:
3. 受限指針(C99):
restrict關鍵詞是一個限定詞,可以被用在指針上。它向編譯器保證,在這個指針的生命周期內,任何通過該指針訪問的內存,都只能被這個指針改變。比如,在
編譯器可能會假設,x和y?所指的并不是同一個int對象,因為如果它們指向了同一個對象,則x的值將可以通過y修改,這正是你保證不會發生的。因此,將允許編譯器來優化f,就好像函數原本被寫做如下這樣:
如果你違反協議向f傳遞兩個指向同一int對象的指針時,將產生未定義行為。
我猜想,引入這一特性最初的動機之一是想讓C語言在數值計算時可以Fortran一樣快。在Fortran 中,默認假定數組不會重疊,因此只有你通過restrict?限定詞來顯式的告訴編譯器數組不能重疊,編譯器才能在C語言中進行這樣的優化。
4. 靜態數組索引(C99)
在
中,你向編譯器保證,你傳遞給f?的指針指向一個具有至少10個int?類型元素的數組的首個元素。我猜這也是為了優化;例如,編譯器將會假定a?非空。編譯器還會在你嘗試要將一個可以被靜態確定為null的指針傳入或是一個數組太小的時候發出警告。
在
你不能修改指針a.,這和說明符int * const a.作用是一樣的。然而,當你結合上一段中提到的static?使用,比如在int a[static const 10]?中,你可以獲得一些使用指針風格無法得到的東西。
5. 泛型表達式(C11)
這個表達式會在編譯期間根據控制表達式的類型,在一個含有一個或多個備選方案的集合中做出選擇。下面這個例子可以很好的說明這一切:
因此,如果expr?是long double類型的,?cbrt(expr)?被轉換為cbrtl(expr),如果是float類型 則轉換為cbrtf(expr)?,或是轉換為cbrt(expr),如果是其他不同的類型(比如說double?)。注意,_Generic?可以用在宏以外的地方,但是用在宏里面最好因為C不允許你進行函數重載。
6.?wint_t?(C99)
我相信大家都知道wint_t?但是?wint_t?到底是個什么鬼東西呢?
好吧,記住fgetc?實際上并不會返回?char?。它會返回int。顯然這是因為fgetc?必須返回返回一個與其他char?都不同的值,也就是EOF,表示到達文件末尾。基于相同的原因,fgetwc?并不返回wchar_t。它會返回一個類型,叫做wint_t?可以表示所有無效wchar_t?類型,包括WEOF,來表示到達文件末尾。
下面這段C程序可以準確的打印2的747次方而不產生誤差。這是為什么呢?
程序:
輸出結果:
答案:
這個問題包含兩個部分。
其一,2的次方可以在double?中被準確的保存而不產生任何精度上的損失(這一結論直到2^1023都是對的,再往后就會產生上溢,得到一個正無窮的值)
另外一部分,很多人猜測是語言實現中的某些特殊情況導致的,但是實際上并非如此。的確,當輸入的數據可以被2的某高次方整除時,有一部分代碼被執行了,但是本質上這只是通常實現工作時的一個副作用。基本上,printf?在打印數字(任何類型)的時候只是做了從二進制到十進制的轉換。并且由于結果對于浮點數可能會過大,printf?的內部實現包含和使用一個大整型實現,盡管在C中并沒有大整型這種變量(在gcc源代碼中,vfprintf.c?和dtoa.c?中包含了很多轉換,如果你想要了解可以一看。)
如果你嘗試打印3^474,
程序:
輸出結果:
結果仍然是一個很大的數且位數也正確,但是這一次卻不夠精確。這里會產生一個相對誤差,因為3^474不能以雙精度浮點數準確的表示。準確的數應該是這樣的143045676882846603471…
譯注:在linux系統上是可以的,在windows 64位上后面會有很多0
我發現一些C語言特性或者是小技巧,我覺得只有很少的人知道。
1. 不使用加號來使數字相加
因為printf()?函數返回它所打印的字符的個數,我們可以利用這一點來使數字相加,代碼如下:
利用位操作同樣也可以做到:
2. 條件運算符的用法
通常我們都這樣使用它:
x = (y < 0) ? 10 : 20;
但是同樣也可以這樣用:
(y < 0 ? x : y) = 20;
3. 在一個返回值為void?的函數中寫一個return?語句
4. 逗號表達式的使用
通常逗號表達式會這樣使用:
但是你可以在其他任何地方使用逗號表達式:
每條語句都進行了求值,但是表達式的值是最后一個語句的值。
5. 將結構體初始化為0
struct mystruct a = {0};
這將把結構體中全部元素初始化為0
6. 多字符常量
int x = 'ABCD';
這會把x的值設置為0×41424344(或者0×44434241,取決于架構)
7.?printf?允許你使用變量來格式化格式說明符本身
*?符號可以達到這一目的
希望這些可以幫助到大家
此致敬禮
你可以在奇怪的地方使用#include
如果你寫:
且fragment.c?包含:
這完全沒有問題。只要#include?包含完整可解析的C表達式,預處理器并不在意它放在什么位置。
1.?printf?格式限定符中指定(POSIX擴展語法)
printf("%4$d %3$d %2$d %1$d", 1, 2, 3, 9); //將會打印9 3 2 1
2. 在scanf?中忽略輸入輸入
scanf("%*d%d", &a);// 如果輸入1 2,則只會得到2
3. 在switch?中使用范圍(gcc擴展語法)
4. 使用前綴ob?來限定常數,使其被當做二進制數(gcc擴展語法)
5.完全正確的最短的C語言程序
譯注:雖然編譯沒有error但是卻不能執行
scanf()的力量
假定我們有一個數組char a[100]
讀取一個字符串:
scanf("%[^\n]\n", a);//表示一直讀取直到遇到'\n',并且忽略掉'\n'
讀取字符串直到遇到逗號:
scanf("%[^,]", a);//但是這次不會忽略逗號
如果你想忽略掉某個輸入,使用在%?后使用*,如果你想要得到John Smith?的姓:
順便提一句,你應該非常小心的使用scanf?因為它可能會是你的輸入緩沖溢出!通常你應該使用fgets?和sscanf?而不是僅僅使用scanf,使用fgets?來讀取一行,然后用sscanf?來解析這一行,就像上面演示的一樣。
~-n?等于n-1
-~n?等于n+1
原因:
當我們寫-n時,實際上是以補碼形式儲存,所以-n?可以寫成~n + 1,吧整個式子放在上面表達式的前面你就能明白原因了。
總結
以上是生活随笔為你收集整理的cbrt c语音_C语言有哪些鲜为人知的特性?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux java文件 core_li
- 下一篇: joi模块验证日期格式_python d