当前位置: 首页 > news >正文

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


相关文章:

  • C/C++标准资料
  • 如果我再次被面试,我会问的几个问题
  • Linux 常用命令记录
  • C++关键字
  • Open Broadcaster Software源码阅读笔记
  • 简单算法--迭代/递归
  • 背包九讲笔记
  • 关于类成员函数中静态变量的一点提示
  • C++ 强制类型转换若干问题
  • 面向对象设计原则
  • C++之父FAQ阅读笔记
  • 要完成的学习或考试任务
  • 类的const、static、const static成员初始化位置及其他需要注意的问题
  • ldd
  • 智能指针
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Angular2开发踩坑系列-生产环境编译
  • create-react-app做的留言板
  • ERLANG 网工修炼笔记 ---- UDP
  • extjs4学习之配置
  • Java IO学习笔记一
  • JS题目及答案整理
  • JWT究竟是什么呢?
  • React Transition Group -- Transition 组件
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 实现简单的正则表达式引擎
  • 使用docker-compose进行多节点部署
  • 小程序开发之路(一)
  • 一起参Ember.js讨论、问答社区。
  • 与 ConTeXt MkIV 官方文档的接驳
  • 正则与JS中的正则
  • No resource identifier found for attribute,RxJava之zip操作符
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 选择阿里云数据库HBase版十大理由
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​Linux·i2c驱动架构​
  • !!java web学习笔记(一到五)
  • # 安徽锐锋科技IDMS系统简介
  • # 计算机视觉入门
  • #大学#套接字
  • #数学建模# 线性规划问题的Matlab求解
  • (C#)获取字符编码的类
  • (笔试题)合法字符串
  • (过滤器)Filter和(监听器)listener
  • (原)Matlab的svmtrain和svmclassify
  • (转)Scala的“=”符号简介
  • (转)编辑寄语:因为爱心,所以美丽
  • ./configure、make、make install 命令
  • .cn根服务器被攻击之后
  • .gitignore文件—git忽略文件
  • .NET 2.0中新增的一些TryGet,TryParse等方法