《编程精粹 - Microsoft编写优质无错C程序秘诀》第3,4章笔记

本文是《编程精粹 - Microsoft编写优质无错C程序秘诀》第3、4章的读书笔记。讨论了如何为子系统设防,包括内存管理中的常见问题和解决方案,如内存分配后的初始化、realloc处理,以及通过填充特定值来检测错误。同时介绍了程序逐条跟踪的重要性,特别是在代码分支和数据流中的错误检测。
摘要由CSDN通过智能技术生成

第三章 为子系统设防

C:\Users\panren\AppData\Roaming\Typora\typora-user-images\image-20210306115322640.png

​ 一个实际的工程往往是有许多的模块组成的,既对应于作者这里说的子系统;比如文件操作相关的文件管理子系统,涉及到文件的打开、关闭、读写和创建。又如内存管理的模块,涉及到内存分配和释放等等。

​ 通常,子系统都要对其实现细节进行隐藏,所隐藏的实现细节可能相当复杂。当子系统编写完成之后,要问自己:“程序员什么情况下会错误地使用这个子系统,在这个子系统中怎样才能自动地检查出这些问题?”在正常情况下,当开始编码排除设计中的危险因素时就应该问过了这个问题。但不管怎样,还应该再问一次。

​ 上面摘抄的是书的原文,注意这里的自动地检查出问题这一点,另外需要强调的是,这本书写于1992年,当时的编译器还没这么强大,现在的编译器已经讲这些问题帮我们解决了,比如非法的指针访问(例如我们使用C++的vector时,如果索引值超过数组边界,编译器会报错,从而提醒我们程序编写地有问题)。

​ C的内存管理过程中会出现下面的问题,这一章节根据下面的问题进行范例教学:

  • 分配一个内存块并使用其中未经初始化的内容;
  • 释放一个内存块但继续引用其中的内容;
  • 调用 realloc 对一个内存块进行扩展,因此原来的内容发生了存储位置的变化,但程序引用的仍是原来存储位置的内容;
  • 分配一个内存块后即“失去”了它,因为没有保存指向所分配内存块的指针;
  • 读写操作越过了所分配内存块的边界;
  • 没有对错误情况进行检查。

1.若隐若现,时有时无

这里使用malloc来举例子

/* fNewMemory ─── 分配一个内存块 */ 
flag fNewMemory(void** ppv, size_t size) 
{
    
    byte** ppb = (byte**)ppv; 
    *ppb = (byte*)malloc(size); 
    return(*ppb != NULL); /* 成功 */ 
}

问题:

如果 malloc 分配成功,那么它返回的内存块的内容无定义,内容随机(PS: C中malloc后一般都会有一个初始化操作)

针对这个问题:

  • 第二章说到的断言能够解决吗?显然不能
  • 用零填充(增加了交付程序的负担,隐瞒错误)
  • 不填充(可能有随机错误,难以发现)

给出的解决办法:

调试版本中填充特点的值(不增加程序负担,消除随机性,暴露错误)

下面是书中给出的解决方案代码

#define bGarbage 0xA3 
// 不同的机器填充内容不同,填写容易出错的值,对于 Macintosh 程序,可以使用值 0xA3
flag fNewMemory(void** ppv, size_t size) 
{
    
    byte** ppb = (byte**)ppv; 
    ASSERT(ppv!=NULL && size!=0); 
    *ppb = (byte*)malloc(size); 
    #ifdef DEBUG 
    {
    
    if( *ppb != NULL ) 
        memset(*ppb, bGarbage, size); //填充        *************************就是这一部分的代码
    }
    #endif 
    return(*ppb != NULL); 
}

说明:这本书写于1992年,当时作者开发使用的系统是Macintosh

在一些 Macintosh 机上,用户使用奇数的指针不能引用 16 或 32 位的值。由此可知,新选择的填充值应该是奇数。另外,如果非法的计数器或索引值较大。就会引起明显的延迟, 或者会使系统的行为显得不正常,从而增大发现这类错误的可能性。因此,所选择的填充值应该是用一个字节能够表示的、看起来很奇怪的较大奇数。我选择 0xA3 不仅因为它能够满足上述的要求,而且因为它还是一条非法的机器语言指令。

而现在已经是2021年了,现在的编译器已经帮助我们做了这样一个工作,下面是VS studio中进行地一个测试

在这里插入图片描述

可以看到分配内存的时候填充了cd,而释放这块内存后填充了dd,下面给出
Visual Studio C++中内存分配的各个填充字符的意义:参考链接

  • 0xABABABAB : Used by Microsoft’s HeapAlloc() to mark “no man’s land” guard bytes after allocated heap memory
  • 0xABADCAFE : A startup to th
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值