C99標準的新特性

注:第一次翻譯國外的博文,英語水平有限,專業詞彙水平也有限,所以更多的是以自己的理解爲基礎的意譯。請參看原文: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

-軟件

http://www.smorgasbordet.com/pellesc/

http://nuwen.net/mingw.html

原文:Features of C99


發佈了130 篇原創文章 · 獲贊 13 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章