C语言的缺陷与陷阱 札记 - 七 可移植性缺陷

21 篇文章 0 订阅

How to Write Protable Software in C    { Prentice-Hall }

  • C 标准与编译器的区别是关键!

  • 标识符名称的限制与区别

           有些C实现将所有字符作为有效字符;

           有些C自动截取长字符的尾部;

           ANSI标准规定,标识符可以为任意长度,但外部名必须至少能由前6个字符唯一地区分,并且不              区分大小写;

       例如:print_float   &   print_fileds    =====  可能带来为危险!

                  STATE  &   State  ===== 这样的命名方式不明智!

                    Malloc & malloc  ===== 可能导致不可预知的境地!

  • 整数的大小

                short  <  int  <  long        

                一个普通(int 类型)整数足够容纳任何数组下标

                字符长度有硬件特性决定 《大多数机器字符长度是8位》

  • 字符的符号

大多数计算机将8位字符当做8位整数处理,但是,并非所有编译器都按照8位整数来解释这些字符——这涉及符号位的解释与处理!当将一个字符转为较大(8Bit以上)整数时候,问题变得棘手!!!

        例如 :  char  -----> int 需要合理的处理掉符号位!!!   -128~127   VS   0~255

        例如 :  char  c  直接使用(unsigned) c 是不能得到与c等价的无符号整数的!因为 其真实的转换过程是   -----    c >>> int >>> unsigned c

  • 移位运算符 (移位比除法快速)

1、向右移位,空出的位置由 0 还是 符号位の副本填充?

            无符号的一定用0填充;有符号的具体采用什么由C语言的具体实现决定!!!

2、移位计数(移位操作的位数)允许最大范围?

            必须严格控制的BIT_WIDTH以内!!!

3、向左移位,符号位符合处理,保留么?

  • 内存位置 0 (NULL)

NULL 只能不指向任何对象。因此除了赋值和比较运算,其他任何使用NULL指针的都是非法!!!

例如: strcmp(NULL,NULL) 是严重危险的

            --- 有的C对内存位置0做了硬件级的读保护,错误使用将立刻停止;

            --- 有的C对内存位置0只允许读;

            --- 有的C对内存位置0不做任何处理>>>>>>极端危险!!!!!

  • 触发运算时发生的截断

q  = a/b;

r   = a%b;

这里假设b!=0。

@1、q*b+r=a  余数关系约束条件;

@2、改变a的正负号,希望q跟着改变,但是q的绝对值不变;

@3、如果b>0, 希望r>=0 且 r<b ;

 三个约束条件无法同时满足,一般的C实现选择支持1、2同时满足!!!

  • 随机数的大小

        早期的C在16位机器上实现随机函数rand(0~2^15-1非负整数)。后来的机器发展到32位,研发人员则实现了rand(0~2^31-1非负整数)。

        如此,则导致了移植的缺陷: 解决办法是提供了一个宏 RAND_MAX 来限定最大随机数!!!

  • 大小写转换

        早期的库函数 toupper  和  tolower 被定义为宏

#define toupper(c)   ( (c) + 'A' - 'a' )

#define tolower(c)   ( (c)  + 'a' - 'A' )

危险之处在于如果c 传入的大小写不对!!!就会返回无效信息!!!

因此一般用法: (  isupper(c)?tolower(c):c  )

        

        为了避免,每次都预先检测,进一步的改进是:

#define toupper(c)   ( (c) >= ‘a’&&  (c) <= 'z'  ?  (c) + 'A' - 'a' : (c) )

#define tolower(c)    ( (c) >= 'A' && (c) <= 'Z' ?  (c) + 'a' - 'A' : (c)  )

        但是: 如果 使用 toupper(*p++)这样又会带来重复计算的危险!!!

 

        最终,采用了两种实现方式,以便于灵活实现:

int toupper(int c)

{

    if(c>='a' && c<='z')

            return c+'A'-'a'

    return c;

}

#define _toupper(c)   ( (c) + 'A' - 'a' )

 

tolowper 也 有类似实现!

  • 首先释放而后重新分配

malloc  realloc  free

realloc :  该函数指针 ptr 所指向内存的大小调整为size字节,返回一个指向调整后内存块(可能改内存块已经被移动过了)的指针。

            假定原来是 oldsize  新的是 newsize, 那么min(oldsize,newsize)中的内容保持不变!!!

  • 可移植性的问题的实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值