设为首页 加入收藏

TOP

c语言高级编程指南1 (翻译)(一)
2014-11-23 18:58:08 来源: 作者: 【 】 浏览:43
Tags:语言 高级 编程 指南 翻译

本文是第一部分,翻译的内容为int类型的转换,内存分配。

c语言是系统程序,嵌入式系统以及很多其他应用程序的一种选择。然而似乎对计算机不是特别感兴趣,才不会去接触c语言,熟悉c语言的各个方面,以及特别多的细节是一个巨大的挑战。本文试着提供较多的资料来阐述其中的一部分。包括:int类型的转换,内存分配,数组的指针转换,显式的内存函数,Interpositioning(不太理解) ,向量变化。

int 溢出和类型转换

很多c语言程序员都倾向于假设对int类型基本的操作是安全的,使用的时候不会过多的去审查。实际上这些操作很容易出问题。思考下后面的代码:
int main(int argc, char** argv) {
    long i = -1;


    if (i < sizeof(i)) {
         printf(OK
);
    }
    else {
         printf(error
);
    }


    return 0;
}

(本人注:结果是error,出乎很多人的意料吧,下面是作者的解释)

导致这样的原因是变量i被转换成了unsigned int类型。所以它的值不再是-1,而是size_t的最大值,这是由于sizeof操作符的类型导致的。
具体的原因在C99/C11标准的常用算术转换章节中找到:
“如果操作符中有unsinged int类型,并且操作符的优先级大于或者等于其他操作符的时候,需要将signed int转换为unsinged int.

size_t在c语言标准中被定义为至少16位的unsinged int 类型。通常size_t的位数是和系统相关的,int类型的大小和size_t至少是相等的,于是上述的规则强行的把变量转换为unsinged int.

(关于sizof的介绍可以查看http://blog.csdn.net/sword_8367/article/details/4868283)

在我们使用int类型大小的是,就会存在一些问题。c语言标准并没有明确的定义short, int ,long ,long long 以及他们unsinged版本的大小。只是把最小的大小强制规定了。以x86_64框架为例子,long类型在linux上为64个字节,相反在64位的windows上仍然是32个字节。为了使代码更好的移植,通常的方法是用长度固定的类型,例如unit16_t 或者int32_t, 他们在C99标准的stdint.h头文件中定义。下面三种int类型在那里被定义:
1明确大小的:uint8_t uint16_t int32_t 等等
2定义类型的最小长度的:uint_least9_t, uint_least16_t, int_least32_t等
3最高效,定义最小长度的:uint_fast8_t, uint_fast16_t, int_fast32_t等

但是不幸的是,使用stdint.h并不能避免所有的问题。”integral promotion rule(int类型转换的规则)里面这样说:
If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.
如果一个int可以表现原始类型所有的值,那么这个值被转换为int,否则转换为unsinged int .这叫做int类型转换,所有其他的类型在int类型转换中不会被改变。
下面的代码在32为上结果为65536, 在16为机器上为0;
uint32_t sum()
{
uint16_t a = 65535;
uint16_t b = 1;
return a+b;
}
int类型转换保持变量的符号,不过一个简单的char类型转换是被转换为有符号数还是无符号数呢?


通常char类型转换要依靠硬件结构和操作系统,通常在特定平台的程序二进制接口中被确定的。如果你发现char被提升为siged char ,下面的代码会打印-128,127(例如x86框架),否则为128,129.gcc加上编译选项-funsigned-char强制的将x86平台上提升为无符号数。
char c = 128;
char d = 129;
printf(%d,%d ,c,d);


内存分配和内存管理

malloc, calloc,realloc,free
malloc分配一个以bytes为单位的,指定大小的,未初始化的内存空间。如果大小为0,返回结果取决于操作系统,在c语言或者POSIX中没有明确说明这个行为.

如果空间大小必须是0,这个结果由编译器决定:返回一个空指针或者是唯一的指针。

malloc(0)通常会返回一个唯一的合法的指针。任何一种返回方式,必须保证在调用free函数的时候,不能报错。其中空指针,free函数不会做任何操作。

所以如果以一个表达式的结果作为malloc的参数的时候,需要测试int越界。

size_t computed_size;

if (elem_size && num > SIZE_MAX / elem_size) {
errno = ENOMEM;
err(1, overflow);
}

computed_size = elem_size*num;

void * calloc(size_t nelem, size_t elsize);
一般情况下,分配一系列相同大小的空间的时候,应该使用calloc,这样不用表达式去计算大小()。另外它会初始化内存空间为0.释放分配的空间,使用free.

void* realloc(void* ptr, unsigned newsize);
realloc将会改变之前分配内存的大小。函数返回的指针指向新的内存位置,里面的内容可能会和原来的内容有相同的部分。如果新分配的大小比原来的大,增加的空间就可能没有被初始化。如果参数中旧指针为空,大小不等于0,那么作用等同于malloc。如果参数中大小为0,旧指针非空,那么产生的结果取决于操作系统。

大部分操作系统去释放旧指针的内存,返回malloc(0)或者返回NULL.例如,windows会释放内存,并且返回NULL,OpenBSD也会释放内存,并且会返回指向大小为0的指针。

如果realloc失败了会返回NULL,并且会留下曾经分配的内存。所以不仅要检测参数是否溢出,当realloc分配失败的时候,还要正确处理旧的内存空间。
#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #define VECTOR_OK 0 #define VECTOR_NULL_ERROR 1 #define VECTOR_SIZE_ERROR 2 #define VECTOR_ALLOC_ERROR 3 struct vector { int *data; size_t size; }; int create_vector(struct vector *
      vc, size_t num) { if (vc == NULL) { return VECTOR_NULL_ERROR; } vc->data = 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
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇建造者模式(Builder) 下一篇GLSL透视矩阵(C语言)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: