注:第一次翻译国外的博文,英语水平有限,专业词汇水平也有限,所以更多的是以自己的理解为基础的意译。请参看原文: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标准的新特性
最新推荐文章于 2022-01-11 22:37:24 发布