注:第一次翻譯國外的博文,英語水平有限,專業詞彙水平也有限,所以更多的是以自己的理解爲基礎的意譯。請參看原文:Features of C99 A Tour of C99 New in C9X
簡介
C99是1999年發佈的C編程 語言標準。C語言是一種簡單、偏底層的編程語言,是系統編程的絕佳語言。這篇文章將爲大家呈現C99標準的一些新特性。這些新特性在C++語言中還沒出 現,所以這些特性對C++程序員來說可能有點陌生。我們從C++的一些小更新開始,然後纔開始講C99特有的特性。文中的所有源碼都經Pelles C IDE 7 測試過,隨着C99標準的流行,這樣源碼應該也可以用其他C編譯器編譯通過。請確保你的C編譯器開啓了支持C99的功能。
支持 int main() 函數不顯式返回函數值
跟C++一樣,如果在int main()函數中沒有return語句,默認return 0;
引入 _Bool 類型
引入了 _Bool 數據類型,_Bool 類似於只能存儲1和0的無符號整數。需要包含頭文件 stdbool.h 。頭文件 stdbool.h 包含了 bool、true、false 宏定義,分別對應 _Bool,1,0 。
#include <stdbool.h> #include <stdio.h> int main(void) { bool b = false; printf("%u\n", b); b = 5 > 3; printf("%u\n", b); b = 0; printf("%u\n", b); b = -987; printf("%u\n", b); }
引入 %zu 格式控制符
格式控制符 %zu 對應於size_t,消除了必須在無符號整形格式控制符 %u,%lu 和最新的 %llu 中選擇的困惑。
#include <stddef.h> #include <stdint.h> #include <stdio.h> int main(void) { size_t sz = SIZE_MAX; printf("%zu\n", sz); }
引入 _func_
_func_ 標識符類似於 const char 數組,存放函數名。
#include <stdio.h> void i_know_my_name(void) { printf("%s\n", __func__); } int main(void) { i_know_my_name(); printf("%s\n", __func__); }
支持可變長度的數組 Variable-length arrays
可變長度數組就是用變量定義其長度的數組,在此之前,只能用常量來定義數組長度。可變數組長度的實現是有爭議的,因爲它在棧中分配內存,而不是在堆中。而大家都知道棧是用來存儲局部變量的,而且在容量上比堆小很多。如果可變數組的長度過大,可能導致棧溢出,引起崩潰。
在線測試// This program will construct and display an n*n identity matrix. #include <stddef.h> #include <stdio.h> int main(void) { size_t n=0; printf("Please input `n': "); scanf("%zu", &n); int matrix[n][n]; for (size_t i=0; i < n; ++i) for (size_t j=0; j < n; ++j) if (i == j) matrix[i][j] = 1; else matrix[i][j] = 0; for (size_t i=0; i < n; ++i) { for (size_t j=0; j < n; ++j) printf("%d ", matrix[i][j]); printf("\n"); } }
引入可變參數宏 Variadic macros
通過使用"…",函數可以接受可變的參數個數。從C99開始,宏也可以實現這一目的。 _VA_ARGS_ 用來擴展參數。
#include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define TIME_PRINTF(format, ...) do { \ time_t t = time(NULL); \ const char *prefix = "%s -> "; \ char time_format_vla[strlen(prefix) + strlen(format) + 1]; \ strcpy(time_format_vla, prefix); \ strcat(time_format_vla, format); \ printf(time_format_vla, ctime(&t), __VA_ARGS__); \ } while (false) int main(void) { srand(time(NULL)); TIME_PRINTF("Hello %s, your number is %d! Please wait...\n\n", "User", rand() % 100); // waste some time for (size_t n=0; n < SIZE_MAX; ++n); // unfortunately, we need to pass at least two parameters TIME_PRINTF("%s", "So how's it going?"); }
指定初始化 Designated initializers
請直接看測試代碼。
#include <ctype.h> #include <stddef.h> #include <stdio.h> int main(void) { char ca[10] = {[4] = 'e', [0] = 'a', [2] = 'c', [1] = 'b', [3] = 'd', [9] = 'z'}; // 0 1 2 3 4 . . . . . . 9 // ca == {'a', 'b', 'c', 'd', 'e', 0, 0, 0, 0, 'z'} printf("Contents of ca:\n "); // the zeros are not printable, because they aren't the '0' character, // so we need to cast them to int so as to print their numeric value for (size_t i=0; i < sizeof ca; ++i) if (isprint(ca[i])) printf("%c ", ca[i]); else printf("%d ", (int)ca[i]); printf("\n\n"); struct Test { char c; int i; float f; }; struct Test t = {.f = 3.14f, .c = 'Z', .i = 10}; printf("Contents of t:\n c == %c\n i == %d\n f == %f\n", t.c, t.i, t.f); }
無名變量 Compound literals
#include <ctype.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <time.h> // this function will change the case of all letters in the message array, // lowercase letters will become uppercase, and vice versa void flip_case(char *message) { printf("flip_case()\n"); printf("Before: %s\n", message); for (size_t i=0, ml = strlen(message); i < ml; ++i) { const char temp = message[i]; if (isupper(temp)) message[i] = tolower(temp); else if (islower(temp)) message[i] = toupper(temp); } printf("After: %s\n\n", message); } // this function will add 10 to an integer i void add_ten(int *i) { printf("add_ten()\n"); printf("Before: %d\n", *i); *i += 10; printf("After: %d\n\n", *i); } // this function will add 1 to even numbers in the numbers array, // only the first n numbers are operated on void kill_evens(int *numbers, size_t n) { printf("kill_evens()\n"); printf("Before: "); for (size_t i=0; i < n; ++i) printf("%d ", numbers[i]); printf("\n"); for (size_t i=0; i < n; ++i) if (numbers[i] % 2 == 0) numbers[i] += 1; printf("After: "); for (size_t i=0; i < n; ++i) printf("%d ", numbers[i]); printf("\n\n"); } int main(void) { flip_case((char[]){"Hello C99 World!"}); add_ten(&(int){5}); kill_evens((int[]){2, 3, 29, 90, 5, 6, 8, 0}, 8); printf("Current time: %s\n", ctime(&(time_t){time(NULL)})); }
更復雜的場合:
在線測試#include <stddef.h> #include <stdio.h> /// /// @brief Appends contents of array `from` to array `to`. /// @pre `limit` != `0` /// @note No operation is performed for a `limit` of `0`. /// @remarks Resulting array is NUL-terminated. /// @param [out] to String to be written to. /// @param limit Maximum number of bytes that string `to` can store, including NUL. /// @param [in] from String to be copied from. /// @returns Size of resulting string (NUL not counted). /// size_t strscat(char *to, size_t limit, const char *from) { size_t s=0; if (limit != 0) { while (to[s] != '\0') ++s; for (size_t i=0; from[i] != '\0' && s < limit - 1; ++i, ++s) to[s] = from[i]; to[s] = '\0'; } return s; } typedef struct { char *to; size_t limit; const char *from; const char *result; size_t retval; } test_t; static size_t tests_failed; static void run_test(test_t *t) { size_t i=0; if (t->retval != strscat(t->to, t->limit, t->from)) { ++tests_failed; return; } while (t->result[i] != '\0' || t->to[i] != '\0') if (t->result[i] != t->to[i]) { ++tests_failed; break; } else ++i; } #define RUN_TEST(...) run_test(&(test_t){__VA_ARGS__}) int main(void) { RUN_TEST( .to = (char[15]){"The Cutty"}, .limit = 15, .from = " Sark is a ship dry-docked in London.", .result = "The Cutty Sark", .retval = 14 ); RUN_TEST( .to = (char[15]){"The Cutty"}, .limit = 0, .from = "this won't get appended", .result = "The Cutty", .retval = 0 ); RUN_TEST( .to = (char[15]){"The Cutty"}, .limit = 15, .from = "!", .result = "The Cutty!", .retval = 10 ); RUN_TEST( .to = (char[]){"The Cutty Sark"}, .limit = 3, .from = "this shouldn't get appended", .result = "The Cutty Sark", .retval = 14 ); RUN_TEST( .to = (char[]){"The Cutty Sark"}, .limit = 1, .from = "this shouldn't get appended, either", .result = "The Cutty Sark", .retval = 14 ); RUN_TEST( .to = (char[]){""}, .limit = 1, .from = "this had better not get appended!", .result = "", .retval = 0 ); (void)fprintf(stderr, "Number of tests failed: %zu.\n", tests_failed); }
後記
希望您閱讀愉快!如果您有任何提高本文質量的建議,歡迎PM我。
可能有幫助的鏈接
-C99相關
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=215
http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
http://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html
-軟件
C99標準的新特性
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.