`

嵌入式高级C笔记01——关键字和运算符

阅读更多
嵌入式高级C笔记01——关键字和运算符

1. 简单数据类型的位长
大小端(endian)
大小端是CPU存放数据的两种不同顺序。对于整型和长整型等数据类型:大端认为在低地址上存放的是这个整数的高位字节,在高地址上存放的是这个整数的低位字节。小端恰好相反。一般来说X86系列CPU为小端的字节序,PowerPC,68K系列则是大端,ARM系列处理器内部是小端,但是可以被配置为访问大端的存储器。可以用以下代码来测试处理器的大小端:

typedef unsigned char BYTE;
int main(){
	unsigned int num,*p;
	p = #
	num = 0;
	*(BYTE *)p = 0xff;
	if(num == oxff)
		printf("this cpu is little endian!\n");
	else
		//num == 0xff000000
		printf("this cpu is big endian!\n");
	return 0;
}
2. unsigned与signed
大多数编译器都约定char是一个有符号数,ARM的编译器再默认情况下认为char是个无符号数。

3. 存储类型关键字
1) auto关键字
默认情况下局部变量的存储类型是自动的,也就是这个变量要么被存储在堆栈中,要么被存储在CPU内部的寄存器中。
2) register关键字
关键字register可以用于自动变量的声明。这个关键字提示编译器将register关键字修饰的自动变量存储在CPU内部的通用寄存器中而不是存储器中。
需要注意的是如果一个自动变量被编译器分配到了CPU内部的寄存器,对这个变量使用&来取地址是毫无意义的,因为许多机器并不为寄存器进行统一编制。下面代码在ARM编译器中可能会造成data Abort
int *test(int *ptr){
	int a;
	if(ptr!=NULL)
	{
		a = *ptr;
		return &a; //如果编译器将其分配进CPU的寄存器,则这个取地址是无效的
	}
	return NULL;
}
3) static关键字
static关键字有三种不同的用途
a. 如果它用于函数内部的局部变量声明,static关键字的作用是改变局部变量的存储类型,从自动变量变成静态变量,这个变量将在编译的时候由编译器分配一个静态的地址空间而非堆栈。
b. 用于函数定义,则类似Java的private
c. 用于全局变量定义,也类似Java的private
4) extern关键字
extern关键字主要有两种使用方法:
a. 在C文件中直接声明某个其他文件中定义的函数或全局变量为extern,从而告诉编译器这个函数或变量是在其他C文件中。
b. 在头文件中声明某个函数或变量为extern然后在需要引用该函数或变量的C文件中包含这个头文件。
以下为例子:
共有2个C文件,分别为file1.c和file2.c在file2.c中定义了函数int fun(int )和全局数组int a[100];在file1.c中的函数main需要调用fun函数和全局数组a。采用第一种方法解决:
/*以下为file1.c*/
extern int a[];
extern int fun(int);
int array[100];
void main(){
	int i;
	for(i = 0;i<100;i++){
		a[i] = i;
		array[i] = fun(a[i]);
	
	}
	return;
}

/*以下为file2.c*/
int a[100];
int fun(int b){

	return b*(b-1);
}

第二种方法(推荐):
		/*以下为file1.c*/
#include "file2.h"
int array[100];
void main(){
	int i;
	for(i = 0;i<100;i++){
		a[i] = i;
		array[i] = fun(a[i]);
	
	}
	return;
}

/*以下为file2.c*/
#include "file2.h"
int a[100];
int fun(int b){

	return b*(b-1);
}

/*以下为file2.h*/

#ifndef _FILE2_H
#define _FILE2_H

extern int a[];
extern int fun(int);
#endif
4. const关键字
利用const关键字声明一个变量是“只读”的,在C语言中这意味着这个变量的值不能改变。注意将只读和常量的概念区分开来。
int const a = 20;
//下面这个声明是错误的,因为a是变量,在编译时候a的值是不确定的
int array[a];

还应该强调的是指针常量和常量指针。

除此之外虽然const关键字没有在本质上改变变量的属性,但是const还是意义非凡的:
首先,const的作用是给读代码的人传达非常有用的信息,然后,通过给编译器的优化器一些附加的信息,使用const也许能产生更紧凑的代码。

5. volatile关键字
一个定义为volatile的变量表示该变量可能会意想不到的被改变。下面是volatile变量的几个例子:
并行设备的硬件寄存器
一个中断服务子程序中会访问到的非自动变量
多线程应用中被几个任务共享的变量。

6. 隐式类型转换
这儿有个著名的陷阱:
void foo(void)
{
	unsigned int a = 6;
	int b = -20;
	(a+b>6)?printf(">6\n"):printf("<=6\n");

}
上面代码的结果是”>6”,因为编译器会将有符号整数转换成无符号整数。
另一个例子:
int a =5000;
int b = 50;
long c =a*b;
这里a*b后把值赋给c可能a*b后超出int范围,最后出现错误。
应该为long c = (long) a*b;
7. 运算符词法分析
首先一个问题:
c = a+++b; 这个是什么意思
在C语言编辑器中有“Token”这样的概念,C语言的某些Token(比如/,*,=等)只有一个字符长,称为单Token。而C语言中其他一些Token以及关键字,函数名,数组名,变量名包含了多个字符,成为多字符Token。C语言在解决问题是有一个原则:每一个Token应该包含尽可能多的字符。
那么上面的表达式意思就是:
c = (a++)+b

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics