参考链接: C c32rtomb()
前言 - 需要点开头
C11标准是C语言标准的第三版(2011年由ISO/IEC发布),前一个标准版本是C99标准。
相比C99,C11有哪些变化呢!!所有的测试全部基于能够和标准贴合的特性平台. 但是绝大部
分来源于 GCC. 这里不妨教大家源码安装最新的GCC吧。
a. 首先去 GNU GCC官网下载最新的 GCC 源码
GCC : https://gcc.gnu.org/
下载最新源码, 安装过程中可能提示下面这句话
configure: error: Building GCC requires GMP 4.2 , MPFR 2.4.0 and MPC 0.8.0 .
说白了缺少上面 GMP,MPFR,MPC 三个组件。 那么开始下载
GMP : ftp://ftp.gnu.org/gnu/gmp/
MPFR: http://www.mpfr.org/mpfr-current/
MPC : ftp://ftp.gnu.org/gnu/mpc/
b. 开始挨个解压安装 GMP → MPFR → MPC → GCC
开始执行命令跑起来。
cd gmp-6.1.2/mkdir gmp-6.1.2-build
cd gmp-6.1.2-build
../configure
我们如果出现
checking for suitable m4... configure: error: No usable m4 in $PATH or /usr/5bin (see config.log for reasons).
不用怕,那就继续安装 m4
m4:ftp://ftp.gnu.org/gnu/m4/
cd m4-1.4.18
mkdir m4-1.4.18-build
cd m4-1.4.18-build
../configure
make
sudo make install
那继续安装 GMP。
cd ../../gmp-6.1.2 /gmp-6.1.2-build
../configure
make
sudo make install
随后就是 MPFR
cd ../../mpfr-3.1.6
mkdir mpfr-3.1.6-build
cd mpfr-3.1.6-build
../configure
make
sudo make install
然后就是 MPC
cd ../../mpc-1.0.3
mkdir mpc-1.0.3-build
cd mpc-1.0.3-build
../configure
make
sudo make install
最后还是回到我们的 gcc
cd ../../gcc-7.2.0
mkdir gcc-7.2.0-build
cd gcc-7.2.0-build
../configure
又是不好意思,提示下面错误信息
configure: error: I suspect your system does not have 32-bit development libraries (libc and headers). If you have them, rerun configure with --enable-multilib. If you do not have them, and want to build a 64-bit-only compiler, rerun configure with –disable-multilib.
继续
../configure --enable-multilib
make
不好意思又来了
checking dynamic linker characteristics... configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES.
Makefile:11923: recipe for target 'configure-stage1-zlib' failed
make[2]: *** [configure-stage1-zlib] Error 1
make[2]: Leaving directory '/home/wangzhi/桌面/gcc-7.2.0/gcc-7.2.0-build'
Makefile:23803: recipe for target 'stage1-bubble' failed
make[1]: *** [stage1-bubble] Error 2
make[1]: Leaving directory '/home/wangzhi/桌面/gcc-7.2.0/gcc-7.2.0-build'
Makefile:933: recipe for target 'all' failed
make: *** [all] Error 2
没关系我们继续搞,存在首次安装GCC不彻底污染问题,清理后继续安装
make distclean
../configure –enable-multilib
make
还是不行更换思路, 走插件全安装
sudo apt-get install gawk
sudo apt-get install gcc-multilib
sudo apt-get install binutils
sudo apt-get install lzip
make distclean
../configure
make
sudo make install
见过漫长的等待,下面就是见证历史奇迹的时候了。
到这里关于 GCC 升级到最新版本问题以及搞定。
正文 - C11标准特性研究
1、对齐处理
alignof(T)返回T的对齐方式,aligned_alloc()以指定字节和对齐方式分配内存,头文件<stdalign.h>
定义了这些内容。我们首先看看 stdalign.h 中定义
/* ISO C1X: 7.15 Alignment <stdalign.h>. */
#ifndef _STDALIGN_H
#define _STDALIGN_H
#ifndef __cplusplus
#define alignas _Alignas
#define alignof _Alignof
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#endif
#endif /* stdalign.h */
alignas 设置内存的对其方式, alignof 返回内存的对其方式。
Aligned.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdalign.h>
#define _INT_NAME (128)
struct names {
int len;
char name[];
};
struct people {
int id;
alignas(struct names) char name[sizeof(struct names) _INT_NAME];
};
static void test_aligned(void) {
printf("sizeof(struct people) = %zu.n", sizeof(struct people));
// 控制内存布局
struct people pe = { 1 };
struct names * name = (struct names *)pe.name;
name->len = _INT_NAME;
strcpy(name->name, "你好吗?");
printf("people len = %d, name = %s.n", pe.id, name->name);
// 测试内存对其
printf("alignof(struct people) = %zu.n", alignof(struct people));
// 接着控制内存布局
alignas(struct names) char xname[sizeof(struct names) _INT_NAME];
struct names * xna = (struct names *)xname;
strcpy(xna->name, "我还行!");
//
// 另一种内存申请, 一种演示, malloc已经够额
// aligned_alloc 相比 malloc 多了第一个参数, 这个参数必须是2的幂
// 在特定嵌入式平台会使用
//
void * ptr = aligned_alloc(alignof(struct names), _INT_NAME);
if (NULL == ptr)
exit(EXIT_FAILURE);
free(ptr);
}
2、 _Noreturn
_Noreturn是个函数修饰符,位置在函数返回类型的前面,声明函数无返回值,
有点类似于gcc的__attribute__((noreturn)),后者在声明语句尾部。
#include <stdio.h>
#include <stdlib.h>
_Noreturn static void _test(void) {
puts("func _test C11 never returns");
abort();
}
int main(int argc, char * argv[]) {
_test();
}
3、 _Generic
_Generic支持轻量级范型编程,可以把一组具有不同类型而却有相同功能的函数抽象为一个接口。
#include <stdio.h>
void sort_insert_int(int a[], int len);
void sort_insert_float(float a[], int len);
void sort_insert_double(double a[], int len);
#define sort_insert(a, len)
_Generic(a,
int * : sort_insert_int,
float * : sort_insert_float,
double * : sort_insert_double)(a, len)
//
// file : generic.c
// test : C11 泛型用法
//
int main(int argc, char * argv[]) {
int a[] = { 1, 2, 5, 3, 4, 11, 23, 34, 33, 55, 11, 12 };
int i, len = sizeof a / sizeof (*a);
sort_insert(a, len);
for (i = 0; i < len; i)
printf("- ", a[i]);
putchar('n');
return 0;
}
#define sort_insert_definition(T)
void
sort_insert_##T (T a[], int len) {
int i, j;
for (i = 1; i < len; i) {
T key = a[j = i];
while (j > 0 && a[j - 1] < key) {
a[j] = a[j - 1];
--j;
}
a[j] = key;
}
}
sort_insert_definition(int)
sort_insert_definition(float)
sort_insert_definition(double)
最终输出结果如下
4、 _Static_assert()
_Static_assert(),静态断言,在编译时刻进行,断言表达式必须是在编译时期可以计算的表达式,
而普通的assert()在运行时刻断言。
#include <stdio.h>
int main(void) {
printf("C version : %ld.n", __STDC_VERSION__);
_Static_assert(__STDC_VERSION__ < 201112L, "It is c11 version");
return 0;
}
其实本质等同于, 真的有点鸡肋
#if __STDC_VERSION__ >= 201112L
# error "It is c11 version"
#endif
5、安全版本的几个函数
gets_s()取代了gets(),原因是后者这个I/O函数的实际缓冲区大小不确定,
以至于发生常见的缓冲区溢出攻击,类似的函数还有其它的。
_Success_(return != 0)
_ACRTIMP char* __cdecl gets_s(
_Out_writes_z_(_Size) char* _Buffer,
_In_ rsize_t _Size
);
目前在 VS 中有这个函数实现. C11 废弃了 gets, 这里是最接近的 api, 相比 fgets 它不会记录最后一个 'n'.
并且会在最后一个字符添加 '