《编写高质量代码:改善c程序代码的125个建议》——建议2-3:使用rsize_t或size_t类型来表示一个对象所占用空间的整数值单位

简介:

本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第1章,建议2-3,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

建议2-3:使用rsize_t或size_t类型来表示一个对象所占用空间的整数值单位

C语言标准规定size_t是一种无符号整数类型,编译器可以根据操作系统的不同而用typedef来定义不同的size_t类型,即在不同的操作系统上所定义的size_t可能不一样。例如在32位操作系统上可以将size_t定义为unsigned int类型,而在64位操作系统上则可以定义为unsigned long int类型,甚至还可以将size_t定义为unsigned long long int类型等,如下面的示例所示。
在GCC的stddef.h文件中将size_t定义为:

#ifndef __SIZE_TYPE__
#define __SIZE_TYPE__ long unsigned int
#endif
#if !(defined (__GNUG__) && defined (size_t))
typedef __SIZE_TYPE__ size_t;
#ifdef __BEOS__
typedef long ssize_t;
#endif /* __BEOS__ */
而在VC++ 2010的crtdefs.h文件中将size_t定义为:
#ifndef _SIZE_T_DEFINED
#ifdef  _WIN64
typedef unsigned __int64    size_t;
#else
typedef _W64 unsigned int   size_t;
#endif
#define _SIZE_T_DEFINED
#endif

从上面的定义可以看出,size_t类型的引入增强了程序在不同平台上的可移植性,而它也正是为了方便系统之间的移植而定义的。size_t类型的变量大小足以保证存储内存中对象的大小,任何表示对象长度的变量,包括作为大小、索引、循环计数和长度的整数值,都可以声明为size_t类型。比如我们常用的sizeof操作符的结果返回的就是size_t类型,该类型保证能容纳实现所建立的最大对象的字节大小。size_t类型的限制是由SIZE_MAX宏指定的。
接下来看看size_t类型的使用示例,如代码清单1-3所示。

代码清单1-3 size_t类型的使用示例
char *copy(size_t n, const char *str) 
{ 
    int i; 
    char *p; 
    if (n == 0) 
    { 
            /* 处理n==0的情况 */
    } 
    p = (char *)malloc(n); 
    if (p == NULL) 
    { 
            /*处理p==NULL的情况 */
    } 
    for ( i = 0; i < n; ++i ) 
    { 
            p[i] = *str++; 
    } 
    return p; 
}

不难发现,代码清单1-3中存在着一个严重的问题:当p所引用的动态分配的缓冲区在n > INT_MAX时将会发生溢出。我们知道,int 类型的限制是由INT_MAX宏指定的,而size_t类型代表的是一个无符号整数类型,它可能包含一个大于INT_MAX的值。因此,当n的值为0 < n <= INT_MAX时,执行循环n次,代码如预期一样正常运行;但当n的值为INT_MAX < n <= SIZE_MAX,且整型变量i的增值超过INT_MAX时,i的值将是从INT_MIN开始的负值。这时,p[i]所引用的内存位置是在p所引用的内存之前,这就会导致写入发生在数组边界之外。
因此,为了避免发生这种潜在性的错误,应该将变量i也声明成size_t类型,如代码清单1-4所示。

代码清单1-4 代码清单1-3的解决方法
char *copy(size_t n, const char *str) 
{ 
    size_t i; 
    char *p; 
    if (n == 0||n>SIZE_MAX) 
    { 
            /* 处理n==0的情况 */
    } 
    p = (char *)malloc(n); 
    if (p == NULL) 
    { 
            /*处理p==NULL的情况 */
    } 
    for ( i = 0; i < n; ++i ) 
    { 
        p[i] = *str++; 
    } 
    return p; 
}

除了size_t类型之外,ISO/IEC TR 24731-1:2007中引入了一种新类型rsize_t,虽然它被定义为size_t类型,但它明确地表示是用于保存单个对象的长度的。
在VC++ 2010的crtdefs.h文件中将rsize_t定义为:

#if __STDC_WANT_SECURE_LIB__
#ifndef _RSIZE_T_DEFINED
typedef size_t rsize_t;
#define _RSIZE_T_DEFINED
#endif
#endif

在支持rsize_t类型的代码中,你可以检查对象的长度,验证它不大于RSIZE_MAX(一个正常单个对象的最大长度),库函数也可以使用rsize_t进行输入校验。
在VC++ 2010的limits.h文件中将RSIZE_MAX定义为:

#if __STDC_WANT_SECURE_LIB__
#ifndef RSIZE_MAX
#define RSIZE_MAX SIZE_MAX
#endif
#endif

这样就消除了示例整数溢出的可能性,现在我们可以将代码清单1-3中的变量i声明成rsize _t类型,同时也可将参数n修改成rsize _t类型,并与RSIZE_MAX进行比较以验证数据的合法范围,如代码清单1-5所示。

代码清单1-5 代码清单1-3的rsize_t解决方法
char *copy(rsize_t n, const char *str) 
{ 
    rsize_t i; 
    char *p; 
    if (n == 0 || n > RSIZE_MAX) 
    { 
            /* 处理n==0|| n > RSIZE_MAX的情况 */
    } 
    p = (char *)malloc(n); 
    if (p == NULL) 
    { 
            /*处理p==NULL的情况 */
    } 
    for (i = 0; i < n; ++i) 
    { 
            p[i] = *str++; 
    } 
    return p; 
}
相关文章
|
6月前
|
存储 人工智能 程序员
溢出、截断、类型提升:从易错代码入手分析整型数据存储与类型转换
这篇文章介绍了关于数据在内存中的存储以及可能出现的溢出问题,包括整型数据的存储方式、取值范围以及溢出的现象和原因。文章通过例子和罗盘图解释了整型数据溢出时的计算过程,并指出在进行运算时要注意数据类型的转换和可能的溢出情况。此外,文章还给出了几个练习题,帮助读者理解和应用这些知识。
207 0
|
存储 Java
[初始java]——规范你的命名规则,变量的使用和注意事项,隐式转化和强制转化
[初始java]——规范你的命名规则,变量的使用和注意事项,隐式转化和强制转化
|
监控 Cloud Native Java
字节码编程,Byte-buddy篇二《监控方法执行耗时动态获取出入参类型和值》
在前面的ASM、Javassist 章节中也有陆续实现过获取方法的出入参信息,但实现的方式还是偏向于字节码控制,尤其ASM,更是需要使用到字节码指令将入参信息压栈操作保存到局部变量用于输出,在这个过程中需要深入了解Java虚拟机规范,否则很不好完成这一项的开发。但!ASM也是性能最牛的。其他的字节码编程框架都是基于它所开发的。
704 0
字节码编程,Byte-buddy篇二《监控方法执行耗时动态获取出入参类型和值》
|
C语言
用函数方法来比较三个数字中的较大值(常规,函数)
用函数方法来比较三个数字中的较大值(常规,函数)
130 0
用函数方法来比较三个数字中的较大值(常规,函数)
|
编译器
个人阿里笔试题目【编写一个编译器,计算代码在内存所需要的字节数】
个人阿里笔试题目【编写一个编译器,计算代码在内存所需要的字节数】
95 0
个人阿里笔试题目【编写一个编译器,计算代码在内存所需要的字节数】
输入一个整形数(最多可以到亿位),然后按汉语的习惯,将其读出来并输出。如1052,读作:一千零五十二。 程序运行示例: 1052 一千零五十二
输入一个整形数(最多可以到亿位),然后按汉语的习惯,将其读出来并输出。如1052,读作:一千零五十二。 程序运行示例: 1052 一千零五十二
181 0
|
小程序
小程序 onLaunch 参数差别
小程序 onLaunch 参数差别
540 0
小程序 onLaunch 参数差别
《编程原本 》一1.2 值
本节书摘来自华章出版社《编程原本 》一书中的第1章,第1.2节,作者(美)斯特潘诺夫(Stepanov, A.),(美)麦克琼斯(McJones, P.),更多章节内容可以访问云栖社区“华章计算机”公众号查看
1076 0