日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C11 标准新特性

發(fā)布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C11 标准新特性 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

C11標(biāo)準(zhǔn)是C語言標(biāo)準(zhǔn)的第三版(2011年由ISO/IEC發(fā)布),前一個標(biāo)準(zhǔn)版本是C99標(biāo)準(zhǔn)。相比C99,C11有哪些變化呢

1、 對齊處理

alignof(T)返回T的對齊方式,aligned_alloc()以指定字節(jié)和對齊方式分配內(nèi)存,頭文件<stdalign.h>定義了這些內(nèi)容。

alignof( 類型標(biāo)識 )
返回 std::size_t 類型值。
返回由類型標(biāo)識所指示的類型的任何實例所要求的對齊字節(jié)數(shù),該類型可以為完整類型、數(shù)組類型或者引用類型。
若類型為引用類型,則運算符返回被引用類型的對齊;若類型為數(shù)組類型,則返回元素類型的對齊要求。

sizeof和alignof對于一般的數(shù)據(jù)類型返回值是相同的,但是對于下面情況特別:

struct Foo {int a;float b;char c; };alignof(Foo) //值為4,對齊長度 sizeof(Foo) //結(jié)構(gòu)體的總大小:12

void *aligned_alloc( size_t alignment, size_t size );
分配 size 字節(jié)未初始化的存儲空間,按照 alignment 指定對齊。 size 參數(shù)必須是 alignment 的整數(shù)倍。
aligned_alloc 是線程安全的:它表現(xiàn)得如同只訪問通過其參數(shù)可見的內(nèi)存區(qū)域,而非任何靜態(tài)存儲。
令 free 或 realloc 歸還一塊內(nèi)存區(qū)域的先前調(diào)用,同步于令 aligned_alloc 分配相同或部分相同的內(nèi)存區(qū)域的調(diào)用。此同步出現(xiàn)于任何解分配函數(shù)所做的內(nèi)存訪問之后,和任何通過 aligned_alloc 所做的內(nèi)存訪問之前。所有操作每塊特定內(nèi)存區(qū)域的分配及解分配函數(shù)擁有單獨全序。
傳遞不是 alignment 整數(shù)倍的 size ,或傳遞實現(xiàn)不支持的 alignment ,會令函數(shù)失敗并返回空指針(出版的 C11 指定此為未定義行為,這已經(jīng)為 DR 460 所更正)

#include <stdio.h> #include <stdlib.h>int main(void) {int *p1 = malloc(10*sizeof *p1);printf("default-aligned addr: %p\n", (void*)p1);free(p1);int *p2 = aligned_alloc(1024, 10*sizeof *p2);printf("1024-byte aligned addr: %p\n", (void*)p2);free(p2); } default-aligned addr: 0x17d6010 1024-byte aligned addr: 0x17d6400

2、 _Noreturn

_Noreturn是個函數(shù)修飾符,位置在函數(shù)返回類型的前面,聲明函數(shù)無返回值,有點類似于gcc的attribute((noreturn)),后者在聲明語句尾部。

_Noreturn function_declaration
_Noreturn 關(guān)鍵詞出現(xiàn)于函數(shù)聲明中,指定函數(shù)不會由于執(zhí)行到 return 語句或抵達(dá)函數(shù)體結(jié)尾而返回(可通過執(zhí)行 longjmp 返回)。若聲明 _Noreturn 的函數(shù)返回,則行為未定義。若編譯器能檢測此錯誤,則推薦編譯器診斷。
_Noreturn 指定符可以在同一函數(shù)聲明中出現(xiàn)多于一次,行為與只出現(xiàn)一次相同。
此指定符通常通過便利宏 noreturn 使用,該宏于頭文件 stdnoreturn.h 提供。

示例:

#include <stdlib.h> #include <stdio.h> #include <stdnoreturn.h>// 在 i <= 0 時導(dǎo)致未定義行為 // 在 i > 0 時退出 noreturn void stop_now(int i) // 或 _Noreturn void stop_now(int i) {if (i > 0) exit(i); }int main(void) {puts("Preparing to stop...");stop_now(2);puts("This code is never executed."); }

輸出:

Preparing to stop...

3、 _Generic

_Generic支持輕量級范型編程,可以把一組具有不同類型而卻有相同功能的函數(shù)抽象為一個接口。

_Generic ( controlling-expression , association-list )
其中 association-list 是逗號分隔的關(guān)聯(lián)列表,每個關(guān)聯(lián)擁有語法:
type-name : expression
default : expression

_Generic. 這個關(guān)鍵字類似與switch語法 :_Generic( ‘a(chǎn)’, char: 1, int: 2, long: 3, default: 0) 輸出為2 (字符在C中為整型).

4、 _Static_assert()

_Static_assert(),靜態(tài)斷言,在編譯時刻進(jìn)行,斷言表達(dá)式必須是在編譯時期可以計算的表達(dá)式,而普通的assert()在運行時刻斷言。

_Static_assert ( 表達(dá)式 , 消息 ) (C11 起)
表達(dá)式 - 任何整數(shù)常量表達(dá)式
消息 - 任何字符串字面量

示例:

#include <assert.h> int main(void) {// 測試數(shù)學(xué)是否正常工作static_assert(2 + 2 == 4, "Whoa dude!"); // 或 _Static_assert(...// 這會在編譯時產(chǎn)生錯誤。static_assert(sizeof(int) < sizeof(char),"this program requires that int is less than char"); }

5、安全版本的幾個函數(shù)

gets_s()取代了gets(),原因是后者這個I/O函數(shù)的實際緩沖區(qū)大小不確定,以至于發(fā)生常見的緩沖區(qū)溢出攻擊,類似的函數(shù)還有其它的。

char *gets( char *str );
從 stdin 讀入 str 所指向的字符數(shù)組,直到發(fā)現(xiàn)換行符或出現(xiàn)文件尾。在讀入數(shù)組的最后一個字符后立即寫入空字符。換行符被舍棄,但不會存儲于緩沖區(qū)中。

char *gets_s( char *str, rsize_t n );
從 stdin 讀取字符直到發(fā)現(xiàn)換行符或出現(xiàn)文件尾。至多寫入 n-1 個字符到 str 所指向的數(shù)組,并始終寫入空終止字符(除非 str 是空指針)。若發(fā)現(xiàn)換行符,則忽略它并且不將它計入寫入緩沖區(qū)的字符數(shù)。
在運行時檢測下列錯誤,并調(diào)用當(dāng)前安裝的制約處理函數(shù):

n 為零 n 大于 RSIZE_MAX str 是空指針 在存儲 n-1 個字符到緩沖區(qū)后沒有遇到換行符或文件尾。

6、 fopen()新模式

fopen()增加了新的創(chuàng)建、打開模式“x”,在文件鎖中比較常用。
以x結(jié)尾的模式為獨占模式,文件已存在或者無法創(chuàng)建(一般是路徑不正確)都會導(dǎo)致fopen失敗.文件以操作系統(tǒng)支持的獨占模式打開.[C11]

7、 匿名結(jié)構(gòu)體、聯(lián)合體。

在 C 語言中,可以在結(jié)構(gòu)體中聲明某個聯(lián)合體(或結(jié)構(gòu)體)而不用指出它的名字,如此之后就可以像使用結(jié)構(gòu)體成員一樣直接使用其中聯(lián)合體(或結(jié)構(gòu)體)的成員。

示例:

#include <stdio.h> struct person { char *name; char gender; int age; int weight; struct { int area_code; long phone_number; }; }; int main(void) { struct person jim = {"jim", 'F', 28, 65, {21, 58545566}}; printf("%d\n", jim.area_code); }

如果不使用匿名結(jié)構(gòu)體,則上述例子對應(yīng)的代碼如下:

#include <stdio.h> struct phone { int area_code; long phone_number; }; struct person { char *name; char gender; int age; int weight; struct phone office; }; int main(void) { struct person jim = {"jim", 'F', 28, 65, {21, 58545566}}; printf("%d\n", jim.office.area_code); }

對比上述兩個例子可以看出:

使用匿名結(jié)構(gòu)體,結(jié)構(gòu)體對象 jim 可以通過 jim.area_code 直接訪問匿名結(jié)構(gòu)體成員變量 area_code,代碼相對比較簡潔

反之則必須通過 jim.office.area_code 來訪問結(jié)構(gòu)體成員變量

8、 多線程
頭文件<threads.h>定義了創(chuàng)建和管理線程的函數(shù),新的存儲類修飾符_Thread_local限定了變量不能在多線程之間共享。

_Thread_local 指示線程存儲期。它不能用于函數(shù)聲明。若將它用在對象聲明上,則它必須在同一對象的每次聲明上都存在。若將它用在塊作用域聲明上,則必須與 static 或 extern 之一組合以決定鏈接。

線程存儲期。存儲期是創(chuàng)建對象的線程的整個執(zhí)行過程,在啟動線程時初始化存儲于對象的值。每個線程擁有其自身的相異對象。若執(zhí)行訪問此對象的表達(dá)式的線程,不是執(zhí)行其初始化的線程,則行為是實現(xiàn)定義的。所有聲明為 _Thread_local 的對象擁有此存儲期。

9、 _Atomic類型修飾符和頭文件<stdatomic.h>。

語法
_Atomic ( type-name ) (1) (C11 起)
_Atomic type-name (2) (C11 起)

用作類型限定符;指代 type-name 的原子版本。在此作用中,它可以與 const 、 volatile 及 restrict 混合使用。盡管不同于其他限定符, type-name 的原子版本可能擁有不同的大小、對齊以及對象表示。

_Atomic const int * p1; // p 是指向 _Atomic const int 的指針 const atomic_int * p2; // 同上 const _Atomic(int) * p3; // 同上

原子類型的對象是僅有的免除數(shù)據(jù)競爭的對象,即它們可以被兩個線程共時修改,或先被一個修改再被另一個讀取。.

每個原子對象都擁有關(guān)聯(lián)于其自身的修改順序,即對該對象的完整修改順序。若從某個線程的視角來看,對于某原子對象M的修改 A 發(fā)生先于同一原子對象 M 的修改 B ,則在 M 的修改順序中 A 的出現(xiàn)先于 B 。

注意即使每個原子對象都有其自身的修改順序,它卻不是全序;不同線程可能會觀測到相異原子對象有相異的修改順序。

對于所有原子運算,保證有四種連貫:

寫寫連貫:若原子對象 M 的修改操作 A 發(fā)生先于 M 的修改操作 B ,則 M 的修改順序中 A 出現(xiàn)早于 B 。 讀讀連貫:若原子對象 M 的值計算 A 發(fā)生先于 M 的值計算 B ,且從 M 上的副效應(yīng)X求得 A 值,則 B 所計算得的值要么是 X 所存儲的值,要么是 M 上的副效應(yīng) Y 所存儲的值,其中 Y 在 M 的修改順序中出現(xiàn)后于 X 。 讀寫連貫:若原子對象 M 的值計算 A 發(fā)生先于 M 上的操作 B ,則從 M 上的副效應(yīng)X求得 A 值,這里 X 在 M 的修改順序中出現(xiàn)先于 B 。 寫讀連貫:若在原子對象 M 上的副效應(yīng) X 發(fā)生先于 M 的值計算 B ,則求值 B 從 X,或從在 M 的修改順序中出現(xiàn)后于 X 的副效應(yīng) Y 求得其值。

一些原子運算亦是同步操作:它們可以擁有附加的釋放語義、獲取語義,或順序一致語義。見 memory_order 。

內(nèi)建的自增減運算符和復(fù)合賦值運算符是擁有完全序列一致順序(如同用 memory_order_seq_cst )的讀-修改-寫操作。若想要更不嚴(yán)格的同步語義,則可以用標(biāo)準(zhǔn)庫函數(shù)替代。

原子屬性僅對左值表達(dá)式有意義。左值到右值轉(zhuǎn)換(其模仿從原子區(qū)域到CPU寄存器的內(nèi)存讀取)會把原子性及其他限定符剝?nèi)ァ?

示例:

#include <stdio.h> #include <threads.h> #include <stdatomic.h>atomic_int acnt; int cnt;int f(void* thr_data) {for(int n = 0; n < 1000; ++n) {++cnt;++acnt;// 對于此例,寬松內(nèi)存順序是足夠的,例如// atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);}return 0; }int main(void) {thrd_t thr[10];for(int n = 0; n < 10; ++n)thrd_create(&thr[n], f, NULL);for(int n = 0; n < 10; ++n)thrd_join(thr[n], NULL);printf("The atomic counter is %u\n", acnt);printf("The non-atomic counter is %u\n", cnt); }

可能的輸出:

The atomic counter is 10000 The non-atomic counter is 8644

10、改進(jìn)的Unicode支持和頭文件<uchar.h>。

語法
” s-char-sequence ” (1)
u8 ” s-char-sequence ” (2) (C11 起)
u ” s-char-sequence ” (3) (C11 起)
U ” s-char-sequence ” (4) (C11 起)
L ” s-char-sequence ” (5)

1) 字符串字面量:字面量類型為 char[] ,用執(zhí)行字符集從 s-char-sequence 中的下個字符初始化數(shù)組中的每個字符。
2) UTF-8 字符串字面量:字面量類型為 char[] ,用 UTF-8 編碼,從 s-char-sequence 中的下個多字節(jié)字符初始化字符數(shù)組中的每個字符。
3) 16 位寬字符串字面量:字面量類型為 char16_t[] ,如同在實現(xiàn)定義的本地環(huán)境中通過執(zhí)行 mbrtoc16 一般初始化數(shù)組中的每個 char16_t 元素。
4) 32 位寬字符串字面量:字面量類型為 char32_t[] ,如同在實現(xiàn)定義的本地環(huán)境中通過執(zhí)行 mbrtoc32 一般初始化數(shù)組中的每個 char32_t 元素。
5) 寬字符串字面量:字面量類型為 wchar_t[] ,如同在實現(xiàn)定義的本地環(huán)境中通過執(zhí)行 mbstowcs 一般初始化數(shù)組中的每個 wchar_t 元素。

示例:

#include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <uchar.h> #include <locale.h> int main(void) {char s1[] = "a貓?"; // 或 "a\u732B\U0001F34C"char s2[] = u8"a貓?";char16_t s3[] = u"a貓?";char32_t s4[] = U"a貓?";wchar_t s5[] = L"a貓?";setlocale(LC_ALL, "en_US.utf8");printf(" \"%s\" is a char[%zu] holding { ", s1, sizeof s1 / sizeof *s1);for(size_t n = 0; n < sizeof s1 / sizeof *s1; ++n) printf("%#x ", +(unsigned char)s1[n]); puts(" }");printf("u8\"%s\" is a char[%zu] holding { ", s2, sizeof s2 / sizeof *s2);for(size_t n = 0; n < sizeof s2 / sizeof *s2; ++n) printf("%#x ", +(unsigned char)s2[n]); puts(" }");printf(" u\"a貓?\" is a char16_t[%zu] holding { ", sizeof s3 / sizeof *s3);for(size_t n = 0; n < sizeof s3 / sizeof *s3; ++n) printf("%#x ", s3[n]); puts(" }");printf(" U\"a貓?\" is a char32_t[%zu] holding { ", sizeof s4 / sizeof *s4);for(size_t n = 0; n < sizeof s4 / sizeof *s4; ++n) printf("%#x ", s4[n]); puts(" }");printf(" L\"%ls\" is a wchar_t[%zu] holding { ", s5, sizeof s5 / sizeof *s5);for(size_t n = 0; n < sizeof s5 / sizeof *s5; ++n) printf("%#x ", (unsigned)s5[n]); puts(" }"); }

可能的輸出:

"a貓?" is a char[9] holding { 0x61 0xe7 0x8c 0xab 0xf0 0x9f 0x8d 0x8c 0 } u8"a貓?" is a char[9] holding { 0x61 0xe7 0x8c 0xab 0xf0 0x9f 0x8d 0x8c 0 }u"a貓?" is a char16_t[5] holding { 0x61 0x732b 0xd83c 0xdf4c 0 }U"a貓?" is a char32_t[4] holding { 0x61 0x732b 0x1f34c 0 }L"a貓?" is a wchar_t[4] holding { 0x61 0x732b 0x1f34c 0 }

11、quick_exit()

又一種終止程序的方式,當(dāng)exit()失敗時用以終止程序。

quick_exit

C

程序支持工具

定義于頭文件

#include <stdlib.h> #include <stdio.h>void f1(void) {puts("pushed first");fflush(stdout); }void f2(void) {puts("pushed second"); }int main(void) {at_quick_exit(f1);at_quick_exit(f2);quick_exit(0); }

輸出:

pushed second pushed first

12、復(fù)數(shù)宏,浮點數(shù)宏。

頭文件 <tgmath.h> 包含頭文件 <math.h> 及 <complex.h> ,并定義了幾種泛型宏。這些宏會根據(jù)參數(shù)類型決定要調(diào)用的實際函數(shù)。

示例:

#include <stdio.h> #include <complex.h> #include <tgmath.h>int main(void) {double complex z1 = I * I; // 虛數(shù)單位平方printf("I * I = %.1f%+.1fi\n", creal(z1), cimag(z1));double complex z2 = pow(I, 2); // 虛數(shù)單位平方printf("pow(I, 2) = %.1f%+.1fi\n", creal(z2), cimag(z2));double PI = acos(-1);double complex z3 = exp(I * PI); // 歐拉公式printf("exp(I*PI) = %.1f%+.1fi\n", creal(z3), cimag(z3));double complex z4 = 1+2*I, z5 = 1-2*I; // 共軛printf("(1+2i)*(1-2i) = %.1f%+.1fi\n", creal(z4*z5), cimag(z4*z5)); }

輸出:

I * I = -1.0+0.0i pow(I, 2) = -1.0+0.0i exp(I*PI) = -1.0+0.0i (1+2i)*(1-2i) = 5.0+0.0i

13、time.h新增timespec結(jié)構(gòu)體,時間單位為納秒,原來的timeval結(jié)構(gòu)體時間單位為毫秒。

struct timespec 定義:

typedef long time_t; #ifndef _TIMESPEC #define _TIMESPEC struct timespec { time_t tv_sec; // seconds long tv_nsec; // and nanoseconds }; #endif

struct timespec有兩個成員,一個是秒,一個是納秒, 所以最高精確度是納秒。
一般由函數(shù)int clock_gettime(clockid_t, struct timespec *)獲取特定時鐘的時間,常用如下4種時鐘:
CLOCK_REALTIME 統(tǒng)當(dāng)前時間,從1970年1.1日算起
CLOCK_MONOTONIC 系統(tǒng)的啟動時間,不能被設(shè)置
CLOCK_PROCESS_CPUTIME_ID 本進(jìn)程運行時間
CLOCK_THREAD_CPUTIME_ID 本線程運行時間
struct tm *localtime(const time_t *clock); //線程不安全
struct tm* localtime_r( const time_t* timer, struct tm* result );//線程安全
size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr );

struct timeval 定義:

struct timeval { time_t tv_sec; // seconds long tv_usec; // microseconds }; struct timezone{ int tz_minuteswest; //miniutes west of Greenwich int tz_dsttime; //type of DST correction };

struct timeval有兩個成員,一個是秒,一個是微秒, 所以最高精確度是微秒。
一般由函數(shù)int gettimeofday(struct timeval *tv, struct timezone *tz)獲取系統(tǒng)的時間

示例:

#include<stdio.h> #include<time.h> #include<sys/time.h>void nowtime_ns() {printf("---------------------------struct timespec---------------------------------------\n"); printf("[time(NULL)] : %ld\n", time(NULL)); struct timespec ts;clock_gettime(CLOCK_REALTIME, &ts);printf("clock_gettime : tv_sec=%ld, tv_nsec=%ld\n", ts.tv_sec, ts.tv_nsec);struct tm t;char date_time[64];strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&ts.tv_sec, &t));printf("clock_gettime : date_time=%s, tv_nsec=%ld\n", date_time, ts.tv_nsec); } void nowtime_us() {printf("---------------------------struct timeval----------------------------------------\n"); printf("[time(NULL)] : %ld\n", time(NULL)); struct timeval us;gettimeofday(&us,NULL);printf("gettimeofday: tv_sec=%ld, tv_usec=%ld\n", us.tv_sec, us.tv_usec);struct tm t;char date_time[64];strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&us.tv_sec, &t));printf("gettimeofday: date_time=%s, tv_usec=%ld\n", date_time, us.tv_usec); }int main(int argc, char* argv[]) {nowtime_ns();printf("\n");nowtime_us();printf("\n");return 0; }nowtime.cpp

執(zhí)行結(jié)果:

$tt
—————————struct timespec—————————————
[time(NULL)] : 1400233995
clock_gettime : tv_sec=1400233995, tv_nsec=828222000
clock_gettime : date_time=2014-05-16 17:53:15, tv_nsec=828222000

—————————struct timeval—————————————-
[time(NULL)] : 1400233995
gettimeofday: tv_sec=1400233995, tv_usec=828342
gettimeofday: date_time=2014-05-16 17:53:15, tv_usec=828342

PS:有關(guān)關(guān)鍵字或者接口的參照可以查看以下地址:

http://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5

總結(jié)

以上是生活随笔為你收集整理的C11 标准新特性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。