首页 > 代码库 > C语言编程积累2

C语言编程积累2

寥寥数笔,记录我的C语言盲点笔记,只为曾经经历过,亦有误,可交流。

1.implict declartion of function 指的是在预处理时没有函数的申明,但该函数在别的函数中进行了编译与调用,编译可以完成链接但是会给出warning,需要提前申明

2. sizeof是一个operand操作符,不能直接对其进行&取地址操作。是一个编译器自动算大小的函数,在预处理时。和宏定义有所类似。
sizeof当然不是函数,它是编译的时候处理的
编译时,编译器推断出sizeof参数的类型,sizeof根据这个类型确定一个整数,所以它可以当常量使用
函数肯定不能当常量使用,函数只能运行时求值

3.
1.C语言中,对结构体指针赋值为NULL时,在未对其进行再次修改前,不允许对该结构体取值,因为NULL=0,取0处的内容,程序运行时会出现段错误Segmentation fault,不要对NULL地址取值。这个错误使得在调用需要指针的函数的最好不要传入指针变量,除非自带获取过一个地址如malloc,calloc等,不然这个地址默认是0,一旦在函数内部发生取值赋值时,就会出现段错误。段错误往往是有对内存的不正当操作引起,使的程序在运行是侵占内存,系统检测到后强制终止程序运行,以防止系统死机。


2.在使用malloc使要确定是否分配所需的内存大小,不然程序访问超出的那些内存时往往不在是你原本想象的数值,系统已经将这些内存自我实现了回收机制,只留下你申请的那部分。也许你能再次访问到这块内存,但是最终的结果肯定是内存已经回收清空,系统这样做的好处就是看不是堆内存链表中的区域,自行回收,使系统更高效。



4.C语言中优良的编程习惯
#ifndef _H_FINGER_API_H_
#define _H_FINGER_API_H_
#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
extern "C" }
#endif

这样的好处在于定义的头文件在一个c源文件中出现多次时,也不会出现重复的函数申明,同时这个也可以将c很方便的移植到c++去中去。

5 C语言中,对结构体指针赋值为NULL时,在未对其进行再次修改前,不允许对该结构体取值,因为NULL=0,取0处的内容,程序运行时会出现段错误Segmentation fault,
不要对NULL地址取值。

6,for(n = 0 ; n < nLen ; n++)和for(int n = 0 ; n < nLen ; n++)
这两个的区别在与后者的n只能在for这个区域中生效,前者在整个函数域内有效。后者的n不能在for外部使用。c中前者的使用较为理想。C99的标准

7,函数间数据的传递也可以考虑使用memcpy来对临时缓存进行拷贝。但是要记得不能在函数内部把一个临时缓存区的地址覆给一个传入的指针变量。因为结束后这部发内容被清空,无意义(除非用malloc申请的内容)

8.全局变量可不可以定义在可被多个.C文件包含的.,h头文件中?为什么?
恩,不可以在多个.c文件使用含有全局变量(已经定义即初始化)的.h文件,因为每个文件域都有了这个全局变量后。在编译连接时,编译器识别到两个全局变量并且都要分配地址,这样的话在放入全局变量区之前就出现连接报错。
解决方法:
1.在.h中申明为extern int a 或者在其他。c文件文件中声明extern int a。这样这个全局变量编译时就不会报错
但是这个如果只有在一个.c文件中出现定义define或者初始化时,而其他.c只是申明的话,那么这个全局变量就不会报错。一般如果变量定义了就会分配内存的。出现多个申明,默认找已经定义的那个作为全局数值。
2.对两个相同的变量都加static,就可以。因为只在自己的文件域内有效,在函数的用法也类似

关键是不允许在.h中定义的全局变量两赋初值(即定义)!,因为.h中赋值后,多个文件一旦使用,就相当与重复了两次变量的初始化赋值。这个不允许。


9.在编码中。在.h的头文件中养成只做函数和变量的申明。在.c文件中来具体实现,以及全局变量的定义等等。

10所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问

11
Linux下面的文件换行符为\n(0x0a),区别于window下面的\n\r(两个字节)
Linux下面EOF 为-1二进制文件为0xff.(-1补码)
EOF是文本文件结束的标志。window下在文本文件中,数据是以字符的ASCⅡ代码值的形式存放,普通字符的ASCⅡ代码的范围是32到127(十进制),EOF的16进制代码为0x1A(十进制为26),因此可以用EOF作为文件结束标志
文本方式 和 二进制方式 的不同在于。 
1. 文本方式只能读取不包括控制字符(换行除外)的文件 (<32)
2. 文本方式会对换行执行翻译。比如windows下,把文件中的/r/n翻译为/n,把写入文件的/n翻译为/r/n;unix下,把文件中的/n翻译为/n,把写入文件的/n翻译为/n。

12.传入函数的指针如果是需要使用的有必要对其进行NULL检测。
13.C语言中的申明不一定只是申明,int a;系统会给默认的定义值。但是定义int a=1,一定是定义。
还有extern int a;则一定是申明,定义在其他地方,这里只是引用而已。
加extern关键字的声明不是定义并且不分配内存(实际上声明是不分配内存的)。实际上,它只是宣称了已经在其它文件中定义的变量的名称和类型。一个变量可以声明多次,但是只能定义一次。声明只有在他同样是定义时才能初始化,因为只有定义才会分配内存

14。在使用数组或者某些结构体前,最好完成对其的初始化{0}.memset或者bzero等,因为在局部函数内部,编译器分配的栈空间,初始数值并不是为0.需要先初始化为需要的默认值,不然有可能对你后续程序有影响,而造成比如Segmentation fault(常常是对内存操作出现的错误比较操作的内容块小于分配的大小等等)


15missing braces around initialize
该问题是在结构提中有多个数组在初始化时,没有对每一个进行初始化,从而会出现这个错误如
typedef struct Usr_Info{
    unsigned char ID[ID_LEN];
    unsigned char Finger[FMD_LEN];
    unsigned int  finsih_flag;// 1:one usr info get finsihed
}USR_INFO;
初始化USR_INFO one = {0},会出现警告,需要对每一部分的数组进行初始化,就这样{{0}.{0}.0}。C99的特点


16
ANSI C说明了三个用于存储空间动态分配的函数
(1) malloc   分配指定字节数的存储区。此存储区中的初始值不确定
(2) calloc   为指定长度的对象,分配能容纳其指定个数的存储空间。该空间中的每一位(bit)都初始化为0
(3) realloc  更改以前分配区的长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定

17 a[]用作函数参数,会退化成指针,即和*a一样,这样写看上去上更明确一点

18,static申明的函数被同一文件内的函数调用后,这个非static的函数照样可以被其他文件的函数调用,从而可以说是间接的进行了调用static函数。

19,怎样打印long long型数 :printf("%I64u\n",a);或者%I64x.
lld打印64位数据类型。
unsigned long long :lld,64位
long unsigned int: ld = unsigned long int一样
以上是C99中新加的

20。fread(以r读的方式打开),fwrite(以a追加的方式打开)如果是操作2进制文件则加为rb,ab

21.
参数入栈时,不足int的,扩展为int后入栈
比如char(-127)扩展成int(-127)
也就是由 10000001 扩展成 11111111 11111111 11111111 10000001
然后你使用%u,也就是将 11111111 11111111 11111111 10000001 当成 unsigned int 来看,那它当然就是 4294967169 了

22
关于类型提升,有符号扩展, 我看了下《Linux C一站式编程》 的15章的3.5节 “编译器如何处理类型转换”的最后一段, 里面最后一段说:
“最后一个例子,把short型转换成int型,对应表中的“signed integer to signed integer”,转换之后应该值不变。那怎么维持值不变呢?是不是在高位补16个0就行了呢?如果原值是-1,十六进制表示就是ffff,要转成int 型的-1需要变成ffffffff,因此需要在高位补16个1而不是16个0。换句话说,要维持值不变,在高位补1还是补0取决于原来的符号位,这称为符号扩展(Sign Extension)。”
   
这是signed integer to signed integer, 为何signed char转为unsigned int时 ,也运用了符号扩展??

23宏定义中使用\来屏蔽换行符,这样后面的内容都可以是该宏定义块的内容,直到出现换行符后就意味着该宏内容结束。

24. 指针与静态数组的sizeof操作
      指针均可看为变量类型的一种。所有指针变量的sizeof 操作结果均为4。
注意:int *p; sizeof(p)=4;
                  但sizeof(*p)相当于sizeof(int);      
      对于静态数组,sizeof可直接计算数组大小;
      例:int a[10];char b[]="hello";
              sizeof(a)等于4*10=40;
              sizeof(b)等于6;
 注意:数组做型参时,数组名称当作指针使用!!
               void  fun(char p[])
               {sizeof(p)等于4}   

25.C语言复合运行:原则是从右向左依次赋值,可以节省内存开销
a*=a;a=-a;a+=a;a/=a,a|=a;a&=a,a^=a;a=~a(取反);
负数的取反和变号不一样。取反对每一位包括符号位做取反操作,取负就是原值变换符合后的补码,原数是正,则是负数的补码存在,原数是负,则以正数的原码存在(正数原码和补码一样)

26. C语言中的volatile告知编译器,这个变量不要被编译器优化成寄存器间接访问变量。无论什么情况下都要使用直接访问(防止特殊的改变,常常指的是硬件引起的变换),volatile易失的,不稳定的
1. volatile变量可变允许除了程序之外的比如硬件来修改他的内容   
2. 访问该数据任何时候都会直接访问该地址处内容,即通过cache提高访问速度的优化被取消。

27 int bit0:1什么意思
位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。为了节省存储空间,并使处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示
typedef union{
unsigned char value;
struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} bit_field;
} PORT;

28 fstat获取文件的大小等基础信息,ftruncate改变文件大小
ftruncate(fd,length),改为length的长度