C语言C99标准、C11标准新增加的特性
C语言标准
C语言从其诞生至今,经历了多个标准的更新,主要标准包括:
- C89/C90 (ANSI C / ISO/IEC 9899:1990) :这是C语言的第一个官方标准,由ANSI于1989年发布,后被ISO采纳为国际标准,发布于1990年。它为C语言的语法、库函数等方面设定了基础规范,广泛被采用并成为后续标准的基础。
- C99 (ISO/IEC 9899:1999) :发布于1999年,C99标准在C89的基础上进行了大量扩展,引入了如可变长度数组(VLAs)、限制指针(
restrict
)、内联函数、复数类型、新的整数类型(如_Bool
)、改进的预处理功能等特性。 - C11 (ISO/IEC 9899:2011) :发布于2011年,C11标准在C99基础上进一步完善,加入了对多线程编程的支持(通过
<threads.h>
库)、增强了Unicode支持(通过<uchar.h>
)、引入了原子操作和线程内存模型、静态断言、匿名结构和联合、宏默认参数等新特性,并提高了语言的安全性。 - C18 (ISO/IEC 9899:2018) :发布于2018年,这个版本主要是对C11标准的小幅修订和澄清,没有引入重大的新特性,主要目的是解决C11标准中发现的问题和歧义,提高标准的清晰度和一致性。C18有时也被视为C11的一个修正版。
目前,最新的官方标准是C18,但需要注意的是,并非所有的编译器都已经完全实现了最新标准的所有特性,开发者在编写代码时应考虑目标编译器的实际支持情况。
C89标准(也称为C90标准)
C89是C语言的第一个官方国际标准,正式名称为ISO/IEC 9899:1990。它是在1989年由美国国家标准协会(ANSI)制定并发布的,故得名C89,随后在1990年被国际标准化组织(ISO)采纳,成为国际标准。C89标准定义了C语言的基础语法、关键字、数据类型,并引入了标准库函数,比如stdio.h
和stdlib.h
等,确立了C语言的基本形态。它的特点是简洁、可移植性强且易于理解,成为了后续C语言教材和实现的基础。
C99标准(ISO/IEC 9899:1999)
C99是C语言的一个重要更新,发布于1999年。它是C89标准的后续版本,引入了许多新特性和改进,旨在适应不断发展的编程需求和技术环境。C99标准增加了诸如限制指针(restrict
)、内联函数、可变长度数组(VLAs)、复数类型(_Complex
)、新的整型常量(如_Bool
)、改进的浮点数处理以及对编译器限制的放宽等特性。此外,C99还引入了//风格的单行注释,使代码更加易读。尽管C99引入了许多现代化的特性,但直到今天,并非所有编译器和开发环境都完全支持C99的所有特性。
下面是一些C99标准新增特性及其示例代码:
1. restrict指针
void copy_memory(void *restrict dest, const void *restrict src, size_t n) {
for(size_t i = 0; i < n; ++i) {
((char*)dest)[i] = ((const char*)src)[i];
}
}
在这个例子中,restrict
关键字告诉编译器,dest
和src
指向的内存区域不会重叠,这使得编译器可以进行更多的优化。
2. 内联函数
inline int add(int a, int b) {
return a + b;
}
使用inline
关键字建议编译器直接将函数体插入每次调用处,以减少函数调用的开销。
3. 可变长度数组(VLAs)
#include <stdio.h>
int main() {
int n = 5;
int arr[n]; // 数组大小在运行时决定
for(int i = 0; i < n; ++i) {
arr[i] = i;
}
for(int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
return 0;
}
这里,数组arr
的大小是在运行时根据变量n
的值确定的。
4. 复数类型
#include <complex.h>
#include <stdio.h>
int main() {
double complex z = 3.0 + 4.0*I;
printf("The complex number is: %f + %fi\n", creal(z), cimag(z));
return 0;
}
使用_Complex
关键字定义复数类型,并通过creal
和cimag
函数获取实部和虚部。
5. 指定成员初始化器
struct Person {
char name[20];
int age;
};
int main() {
struct Person p = {.name = "Alice", .age = 30};
printf("Name: %s, Age: %d\n", p.name, p.age);
return 0;
}
在结构体初始化时,可以直接指定成员的名字进行初始化,提高了代码的清晰度。
6. 对齐处理
#include <stdalign.h>
alignas(16) char buffer[100]; // 确保buffer对齐在16字节边界上
int main() {
// ... 使用对齐后的buffer
return 0;
}
使用_Alignas
关键字可以指定变量或类型的对齐要求。
C11 (ISO/IEC 9899:2011)
C11标准引入了若干新特性,以下是一些主要特性的示例代码:
1. 多线程支持
#include <threads.h>
#include <stdio.h>
void thread_function(void* arg) {
printf("Hello, World! from thread\n");
}
int main() {
thrd_t t;
if(thrd_create(&t, thread_function, NULL) == thrd_success) {
thrd_join(t, NULL); // 等待线程结束
}
printf("Hello, World! from main thread\n");
return 0;
}
这段代码展示了如何使用C11中的<threads.h>
库创建和等待一个线程完成。
2. Unicode支持
#include <stdio.h>
#include <uchar.h>
int main() {
char32_t unicode_char = U'ação'; // 使用UTF-32编码存储Unicode字符
printf("Unicode character: %C\n", unicode_char);
return 0;
}
通过<uchar.h>
头文件,可以使用Unicode字符,并利用宽字符输出函数打印。
3. 静态断言
#include <assert.h>
#define MAX_SIZE 100
void func(int size) {
_Static_assert(size <= MAX_SIZE, "size exceeds maximum allowed");
// ... 函数逻辑
}
int main() {
func(99); // 正常执行
// func(101); // 如果取消注释,编译时会报错
return 0;
}
_Static_assert
允许在编译时验证条件,如果条件不满足,则编译失败。
4. 匿名结构与联合
#include <stdio.h>
struct Info {
int id;
union {
char name[20];
// 可以有其他成员
};
};
int main() {
struct Info info = {1, "Alice"};
printf("ID: %d, Name: %s\n", info.id, info.name);
return 0;
}
C11允许在结构体内部直接定义匿名的联合,简化了结构体的设计。
5. 原子类型和操作
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int counter = ATOMIC_VAR_INIT(0);
void increment(void* arg) {
for(int i = 0; i < 100000; ++i) {
atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);
}
}
int main() {
thrd_t threads[10];
for(int i = 0; i < 10; ++i) {
thrd_create(&threads[i], increment, NULL);
}
for(int i = 0; i < 10; ++i) {
thrd_join(threads[i], NULL);
}
printf("Counter: %d\n", atomic_load_explicit(&counter, memory_order_relaxed));
return 0;
}
通过<stdatomic.h>
头文件,可以使用原子类型和操作进行线程安全的计数,这里展示了如何在多线程环境下安全地增加一个计数器的值。
- 点赞
- 收藏
- 关注作者
评论(0)