你所不知道的C语言高级用法

整形溢出和提升大部分 C 程序员都以为基本的整形操作都是安全的其实不然,看下面这个例子,你觉得输出结果是什么:
int main(int argc, char** argv) {long i = -1;if (i < sizeof(i)) {printf("OKn");}else {printf("errorn");}return 0;}当一个变量转换成无符号整形时,i的值不再是-1,而是 size_t的最大值,因为sizeof操作返回的是一个 size_t类型的无符号数 。在C99/C11标准里写道:

“If the operand that has unsigned integer type has rank greater orequal to the rank of the type of the other operand, then the operandwith signed integer type is converted to the type of the operand withunsigned integer type.”
在C标准里面 size_t至少是一个 16 位的无符号整数,对于给定的架构 size_t 一般对应long,所以sizeof(int)和size_t至少相等,这就带来了可移植性的问题,C标准没有定义 short, int,long,longlong的大小,只是说明了他们的最小长度,对于 x86_64 架构,long在linux下是64位,而在64位windows下是32位 。一般的方法是采用固定长度的类型比如定义在C99头文件stdint.h中的uint16_t,int32_t,uint_least16_t,uint_fast16_t等 。
你所不知道的C语言高级用法

文章插图
 
如果 int可以表示原始类型的所有值,那么这个操作数会转换成 int,否则他会转换成 unsigned int 。下面这个函数在 32 位平台返回 65536,但是在 16 位系统返回 0 。
uint32_t sum(){uint16_t a = 65535;uint16_t b = 1;return a+b;}对于char 类型到底是 signed 还是 unsigned 取决于硬件架构和操作系统,通常由特定平台的 ABI(Application Binary Interface) 指定,如果是 signed char,下面的代码输出-128 和-127,否则输出 128,129(x86 架构) 。
char c = 128;char d = 129;printf("%d,%dn",c,d);内存管理和分配malloc 函数分配制定字节大小的内存,对象未被初始化,如果 size 是 0 取决与系统实现 。malloc(0)返回一个空指针或者 unique pointer,如果 size 是表达式的运算结果,确保没有整形溢出 。
“If the size of the space requested is 0, the behavior isimplementation- defined: the value returned shall be either a nullpointer or a unique pointer.”
size_t computed_size;if (elem_size && num > SIZE_MAX / elem_size) {errno = ENOMEM;err(1, "overflow");}computed_size = elem_size*num;malloc不会给分配的内存初始化,如果要对新分配的内存初始化,可以用calloc代替malloc,一般情况下给序列分配相等大小的元素时,用calloc来代替用表达式计算大小,calloc 会把内存初始化为 0 。
你所不知道的C语言高级用法

文章插图
 
realloc 用来对已经分配内存的对象改变大小,如果新的 size 更大,额外的空间没 有 被 初 始 化 , 如 果 提 供 给 realloc 的 指 针 是 空 指 针 , realloc 就 等 效 于malloc,如果原指针非空而 new size是0,结果依赖于操作系统的具体实现 。
“In case of failure realloc shall return NULL and leave provided memoryobject intact. Thus it is important not only to check for integeroverflow of size argument, but also to correctly handle object size ifrealloc fails.”
下面这段代码可以带你领会malloc,calloc,realloc,free的用法:
【你所不知道的C语言高级用法】#include <stdio.h>#include <stdint.h>#include <malloc.h>#include <errno.h>#define VECTOR_OK0#define VECTOR_NULL_ERROR1#define VECTOR_SIZE_ERROR2#define VECTOR_ALLOC_ERROR3struct vector {int *data;size_t size;};int create_vector(struct vector *vc, size_t num) {if (vc == NULL) {return VECTOR_NULL_ERROR;}vc->data = https://www.isolves.com/it/cxkf/yy/C/2020-08-05/0;vc->size = 0;/* check for integer and SIZE_MAX overflow */if (num == 0 || SIZE_MAX / num < sizeof(int)) {errno = ENOMEM;return VECTOR_SIZE_ERROR;}vc->data = calloc(num, sizeof(int));/* calloc faild */if (vc->data == NULL) {return VECTOR_ALLOC_ERROR;}vc->size = num * sizeof(int);return VECTOR_OK;}int grow_vector(struct vector *vc) {void *newptr = 0;size_t newsize;if (vc == NULL) {return VECTOR_NULL_ERROR;}/* check for integer and SIZE_MAX overflow */if (vc->size == 0 || SIZE_MAX / 2 < vc->size) {errno = ENOMEM;return VECTOR_SIZE_ERROR;}newsize = vc->size * 2;newptr = realloc(vc->data, newsize);/* realloc faild; vector stays intact size was not changed */if (newptr == NULL) {return VECTOR_ALLOC_ERROR;}/* upon success; update new address and size */vc->data = newptr;vc->size = newsize;return VECTOR_OK;}


    推荐阅读