全国服务热线:400-6263-721

位置:太原少儿编程培训学校 > 学校动态 > C语言的可移植性缺陷

C语言的可移植性缺陷

来源:太原少儿编程培训学校时间:2022/11/16 15:47:58

  1. 标识符名称的缺陷

  某些C语言实现把一个标识符中出现的所有字符都当作有效字符处理,而另一些C语言实现却会自动地截断一个长标识符名称的尾部。链接器也会对它能够处理的名称强加限制,例如外部名称中只允许使用大写字母。

  ANSI C标准所能增加的只是,C实现必须能够区别出个字符不同的外部名称。而且这个定义中并没有区分大小写。

  这个程序演示了一个能够确保检测到内存耗尽的简单办法。

  char *Malloc(unsigned n)

  {

  char *p,*malloc(unsigned);

  p=malloc(n);

  if(p==NULL)

  panic("out of memory");

  return p;

  }

  1

  2

  3

  4

  5

  6

  7

  8

  然而,如果这个函数的编译环境是不区分外部名称大小写的C语言实现,此时Malloc和malloc函数实际上是等同的。也就是说,上面的函数不会调用malloc函数,而是会调用它本身,那么它将会引发灾难性的后果!

  2. 整数的大小

  C语言中有三种不同长度的整型:short型、int型、long型。C语言中的字符行为方式与小整数相似。

  这三种类型的长度是非递减的。

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

  字符长度由硬件特性决定。

  现代大多数的机器的字符长度是8位,也有一些机器是9位,然而,现在越来越多的C语言实现中的字符长度都是16位。

  ANSI标准要求long型整数的长度至少应该是32位,而short型和int型整数的长度至少应该是16位。

  3. 字符是有符号整数还是无符号整数

  现代大多数计算机都支持8位字符,因此大多数现代C编译器都把字符实现为8位整数。然而,并非所有的编译器都按照同样的方式来解释这些8位数值。

  只有在我们需要把一个字符值转换为个较大的整数时,这个问题才变得重要起来。而在其他情况下,结果都是已定义的:多余的位将被简单地“丢弃”。编译器在转换char类型到int类型时,需要做出选择:应该将字符作为有符号数处理,还是应该将字符作为无符号数处理?如果是种情况,编译器在将char类型的数扩展到int类型时,应该同时复制符号位;而如果是后种情况,编译器只需在多余的位上直接填充0即可。

  如果一个字符的较高位是1, 编译器是将该字符当作有符号数,还是无符号数呢?对于任何一个需要处理该字符的程序员来说,上述选择的结果非常重要。它决定着一个8位字符的取值范围是 -128~127,还是 0~255 。而这一点又反过来影响到程序员对哈希表或转换表等的设计方式。

  如果编程人员关注一个较高位是1的字符其数值究竟是正还是负,则应该将这个字符声明为无符号字符( unsigned char)。这样,无论是什么编译器,在将该字符转换为整数时,都只需将多余的位填充为0即可。而如果声明为一般的字符变量,那么在某些编译器上可能会作为有符号数处理,在另些编译器上又会作为无符号数处理。

  与此相关的一个常见错误认识是:如果 c 是一个字符变量,使用语句:

  (unsigned) c

  1

  就可得到与c等价的无符号整数。这是会失败的,因为在将字符c转换为无符号整数时,c将首先被转换为int型整数,而此时可能得到非预期的结果。

  正确的方式是使用语句:

  (unsigned char)c

  1

  因为个 unsigned char类型的字符在转换为无符号整数时无须首先转换为int型整数,而是直接进行转换。

  4. 移位操作符

  即使C实现将符号位复制到空出的位中,有符号整数的向右移位运算也并不等同于除以2的某次幂。要证明这一点, 让我们考虑(-1)>>1,这个操作的结果一般不可能为0,但是(-1)/2 在大多数C实现上的求值结果都是0。这意味着以除法运算来代替移位运算,将可能导致程序运行速度大大减慢。举例来说,如果已知下面表达式中的low+high为非负,那么

  mid= (low + high) >> 1;

  1

  与下式

  mid= (low + high ) / 2;

  1

  完全等效,而且前者的执行速度也要快得多。

  5. 内存位置为0

  对NULL指针进行解引用是非法的,但是对NULL指针进行解引用会得到什么后果?

  某些C语言实现对内存位置0强加了硬件级的读保护,在其上工作的程序如果错误使用了一个NULL指针,将立即终止执行。

  其他些C语言实现对内存位置0只允许读,不允许写。在这种情况下,一个NULL指针似乎指向的是某个字符串,但其内容通常不过是一堆“垃圾信息”。

  还有一些c语言实现对内存位置0既允许读,也允许写。在这种实现上面工作的程序如果错误使用了一个NULL指针,则很可能覆盖操作系统的部分内容,造成彻底的灾难!

  严格说来,这并非一个可移植性问题:在所有的C程序中,误用NULL指针的效果都是未定义的。然而,这样的程序有可能在某个C语言实现上“似乎”能够工作,只有当该程序转移到另一台机器上运行时问题才会暴露出来。

  6. 随机数的大小

  rand函数,作用是产生一个(伪)随机非负整数。

  如果在程序中使用rand函数,在移植时就必须根据特定的C语言实现做出"裁剪"。

  ANSI C标准中定义了一个常事RAND_MAX,它的值等于随机数的较大取值。

  7.习题

  习题1: 如果一个机器的字符长度为8个字符,那么其整数长度很可能是16位或32位。请问原因是什么?

  答:某些机器为每个字符分配一个的内存地址,而另一些机器却是按字来对内存寻址。按字寻址的机器通常都存在不能有效处理字符数据的问题,因为要从内存中取得一个字符,就必须读取整个字的内容,然后把不需要用到的部分都丢弃。

  由于按字符寻址的机型在字符处理方面具有效率优势,它们相对于按字寻址的机型,近年来要更为流行。然而,即使对于按字符寻址的机器,在进行整数运算时字的概念也仍然是重要的。因为字符在内存中的存储位置是连续的,所以一个字中包含的字符数,将决定在内存中连续存放的字的地址。

  如果一个字中包含的字符数是2的某次幂,因为乘以2的某次幂的运算可以转换为移位运算,所以计算机硬件就能很容易地完成从字符地址到字地址的转换。

  因此,我们可以合理地预期,字的长度是字符长度的2的某次幂。那么整数的长度为什么不是64位呢?当然,某些时候这样做无疑是有用的。但是,对于那些具有浮点运算硬件的机器,这样做的意义就不大了,而且考虑到我们并不经常需要用到64位整数这样的精度,实现64位整数的代价就过于昂贵。如果只是偶尔用到,我们完全可以用软件来模拟64位(或者更长)的整数,而且丝毫不影响效率。

领取试听课
每天限量名额,先到先得

尊重原创文章,转载请注明出处与链接:http://www.peixun360.com/115/news/575430/违者必究! 以上就是太原少儿编程培训学校 小编为您整理 C语言的可移植性缺陷的全部内容。

温馨提示:提交留言后老师会第一时间与您联系!热线电话:400-6263-721