【ACCESS精品源码栏目提醒】:本文主要为网学会员提供“ARM专业知识积累 - 其它资料”,希望对需要ARM专业知识积累 - 其它资料网友有所帮助,学习一下!
RAM SRAM DRAM SDRAM ROM PROM EEPROMNAND FLASH NOR FLASH !先说 RAM 吧!由字面意思就可以理解,SDRAM SRAM DRAM 都可以统称 RAM,random
access memory的缩写,只是前面加了几个修饰词而已。
SRAM:静态随机存储器,就是它不需要刷新电路,不像动态随机存储器那样,每隔一段时间就要刷新一次数据。
但是他集成度比较低,不适合做容量大的内存,一般是用在处理器的缓存里面。
像 S3C2440 的 ARM9 处理器里面就有 4K 的 SRAM 用来做 CPU 启动时用的。
SDRAM:同步动态随机存储器,像电脑的内存就是用的这种 RAM 叫 DDR SDRAM。
其集成度非常高,因为是动态的,所以必须有刷新电路,每隔一段时间必须得刷新数据。
其存储单元不是按线性排列的,是分页的。
一般的嵌入式产品里面的内存都是用的 SDRAM。
DRAM:动态随机存储器,SDRAM 只是其中的一种吧,没用过,不怎么清楚。
ROM:只读存储器的总称。
PROM:可编程只读存储器,只能写一次,写错了就得报废,现在用得很少了,好像那些成本比较低的 OPT 单片机里面用的就是这种存储器吧。
EPROM:可擦除可编程存储器,这东西也比较古老了,是 EEPROM 的前身,在芯片的上面有个窗口,通过紫外线的照射来擦除数据。
非常之麻烦。
EEPROM:电可擦除可编程只读存储器,比之 EPROM 就先进点了,可以用电来擦除里面对数据,也是现在用得比较多的存储器,比如 24CXX 系列的 EEPROM。
NOR 采用的并行接口,NANDFLASH 和 NORFLASH 都是现在用得比较多的非易失性闪存。
其特点读取的速度比之 NAND 快很多倍,其程序可以直接在 NOR 里面运行。
但是它的擦除速度比较慢,集成度低,成本高。
现在的 NOR 的容量一般在 2M 左右,一般是用在代码量小的嵌入式产品方面。
还有就是在 ARM9 的开发板上可以看见。
而 NAND 呢,采用的是串行的接口,CPU 从里面读取数据的速度很慢,所以一般用 NAND做闪存的话就必须把 NAND 里面的数据先读到内存里面,然后 CPU 才能够执行。
就跟电脑的硬盘样的。
但是它的集成度很高,我的 ARM9 的开发板上面一块 256M 的 NAND 还没有一块 2M 的 NOR 的一半大,所以成本很低。
还有就是它的擦除速度也的 NOR 要快。
要不然的话那就真的悲剧了,假如擦除一块 2M 的 NOR 要一分钟,如果 NAND 的擦除速度比NOR 还要慢,那擦除一块 256M 的 NAND 不是要几个小时。
NAND 一般是用在那些要跑大型的操作系统的嵌入式产品上面,比如 LINUX 啊,WINCE 啊。
NOR 可是可以跑,可以把LINUX 操作系统剪裁到 2M 以内,一个产品难道只去跑系统吗?用户的应用程序呢!其实很多时候,一个嵌入式产品里面,操作系统占的存储空间只是一小部分,大部分都是给用户跑应用程序的。
就像电脑,硬盘都是几百 G,可是 WINDOWNS 操作系统所占的空间也不过几 G 而已。
CONST:const 是一个 C 语言的关键字,它限定一个变量不允许被改变。
使用 const 在一定程度上可以提高程序的安全性和可靠性。
例:为什么下面的例子在使用一个 const 变量来初始化数组,ANSI C 的编译器会报告一个错误呢? const int n 5 int an 答案与分析: 1)这个问题讨论的是“常量”与“只读变量”的区别。
常量,例如 5, abc,等,肯定是只读的,因为常量是被编译器放在内存中的只读区域,当然也就不能够去修改它。
而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。
C 语言关键字 const 就是用来限定一个变量不允许被改变的修饰符(Qualifier)。
上述代码中变量 n 被修饰为只读变量,可惜再怎么修饰也不是常量。
而 ANSI C 规定数组定义时长度必须是“常量”,“只读变量”也是不可以的,“常量”不等于“不可变的变量”。
2)但是在标准 C中,这样定义的是一个常量,这种写法是对的。
实际上,根据编译过程及内存分配来看,这种用法本来就应该是合理的,只是 ANSI C 对数组的规定限制了它(实际上用 GCC 或 VS2005 编译以上代码,确实没有错误产生,也没有给出警告)。
3)那么,在 ANSI C 中用什么来定义常量呢?答案是 enum 类型和define 宏,这两个都可以用来定义常量。
例:下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢? typedef char pStr char string4 abc const char p1 string //1 式 const pStr p2 string //2 式 p1 p2 答案与分析: 问题出在 p2上。
1)const 使用的基本形式: const type m 限定 m 不可变。
2)替换基本形式中的 m 为 1 式中的p1,替换后 const char p1 限定p1 不可变,当然 p1 是可变的,因此问题中 p1是对的。
3)替换基本形式中的 type 为 2 式中的 pStr,替换后 const pStr m 限定 m 不可变,题中的 pStr 就是一种新类型,因此问题中 p2 不可变,p2是错误的。
下面分别用 const 限定不可变的内容是什么? 1)const 在前面 const int nValue; //nValue 是 const const char pContent //pContent 是 const pContent 可变 const char const pContent //pContent 和pContent 都是 const 2)const 在后面,与上面的声明对等 int const nValue //nValue 是 const char const pContent //pContent 是 const pContent 可变 char const pContent //pContent 是 constpContent 可变 char const const pContent //pContent 和pContent 都是 const 答案与分析: const 和指针一起使用是 C 语言中一个很常见的困惑之处,const 只修饰其后的变量,至于 const 放在类型前还是类型后并没有区别。
如:const int a 和 int const a 都是修饰 a 为 const。
不是一种类型,如果pType 之前是某类型,那么 pType 是指向该类型的指针 一个简单的判断方法:指针运算符,是从右到左,那么如:char const pContent,可以理解为 char const pContent,即 pContent 为 const,而 pContent 则是可变的。
int const p1p2 p2 是 const;p1是一整体,因此p1是 const,但 p1 是可变的。
int p1p2 只代表 p1 是指向整型的指针,要表示 p1、p2 都是指针是需写成 int p1 p2。
所以无论是 const p1p2 还是 const p1p2,里面的都是属于 p1 的。
int const const p1p2 p2 是 const,是前一个 const 修饰的,p1 也被前一个 const 修饰,而 p1 被后一个const 修饰。
int const p1p2 ( p1 是 const, const p1)是整体,所以 const 不修饰 p2。
指针指向及其指向变量的值的变化 const 在的左边,则指针指向的变量的值不可变;在的右边,则指针的指向不可变。
简记为“左定值,右定向”。
1)指针指向的变量的值不能变,指向可变 int x 1 int y 2 const int px x int const px x//这两句表达式一样效果 px y //正确,允许改变指向 px 3 //错误,不允许改变指针指向的变量的值 2)指针指向的变量的值可以改变,指向不可变 int x 1 int y 2 int const px x px y //错误,不允许改变指针指向 px 3 //正确,允许改变指针指向的变量的值 3)指针指向的变量的值不可变,指向不可变 int x 1 int y 2 const int const px x int const const px x px y //错误,不允许改变指针指向 px 3 //错误,不允许改变指针指向的变量的值补充 在 c 中,对于 const 定义的指针,不赋初值编译不报错, 即 int const px等不会报错。
但是,在 C中 int const px和 const int const px会报错,const int px不报错。
必须初始化指针的指向 int const px xconst int const pxx 强烈建议在初始化时说明指针的指向,防止出现野指针!perror: include include//注意 不可以掉了这个头文件,perror 是包含在这个文件里的//定义函数 void perrorconst char s perror open_port函数说明 perror 用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 设备stderr 。
参数 s 所指的字符串会先打印出后面再加上错误原因字符串。
此错误原因依照全局变量 errno 的值来决定要输出的字符串。
在库函数中有个 errno 变量,每个 errno 值对应着以字符串表示的错误类型。
当你调用某些函数出错时,该函数已经重新设置了 errno 的值。
perror 函数只是将你输入的一些信息和现在的 errno 所对应的错误一起输出。
范例 include int mainvoid FILE fp fp fopen /root/noexitfile r if NULL fp perror/root/noexitfile return 0 运行结果 rootlocalhost io gcc perror.c rootlocalhost io ./a.out /root/noexitfile: No such file or directoryErrno: errno - number of last error errno 记录系统的最后一次错误代码。
代码是一个 int 型的值,在 errno.h 中定义 if somecall -1 printfsomecall failedn if errno ... ... 这样的例子并不能得到 somecall 这个函数的运行所产生的错误代码,因为很可能是printf 这个函数产生的。
if somecall -1 int errsv errno printfsomecall failedn if errsv ... ... 这样才能真正得到运行 somecall 函数多带来的错误代码。
注意:只有当一个库函数失败时,errno 才会被设置。
当函数成功运行时,errno 的值不会被修改。
这意味着我们不能通过测试 errno 的值来判断是否有错误存在。
反之,只有当被调用的函数提示有错误发生时检查 errno 的值才有意义。
查看错误代码 errno 是调试程序的一个重要方法。
当 linux C api 函数发生异常时一般会将errno 变量需 include errno.h赋一个整数值不同的值表示不同的含义可以通过查看该值推测出错的原因。
在实际编程中用这一招解决了不少原本看来莫名其妙的问题。
比较麻烦的是每次都要去 linux 源代码里面查找错误代码的含义,现在把它贴出来,以后需要查时就来这里看了。
编辑本段 errno 的一些错误定义:以下来自 linux 2.4.20-18 的内核代码中的/usr/include/asm/errno.hstrncpy函数:原型:extern char strncpychar dest char src int n用法:include功能:把 src 所指由 NULL 结束的字符串的前 n 个字节复制到 dest 所指的数组中。
说明:如果 src 的前 n 个字节不含 NULL 字符,则结果不会以 NULL 字符结束。
如果 src 的长度小于 n 个字节,则以 NULL 填充 dest 直到复制完 n 个字节。
src 和 dest 所指内存区域不可以重叠且 dest 必须有足够的空间来容纳 src 的字符串。
返回指向 dest 的指针(该指向 dest 的最后一个元素)strcpy strncpy strlcpy 地用法:好多人已经知道利用 strncpy 替代 strcpy 来防止缓冲区越界。
但是如果还要考虑运行效率的话,也许 strlcpy 是一个更好的方式。
1. strcpy我们知道,strcpy 是依据 0 作为结束判断的,如果 to 的空间不够,则会引起 bufferoverflow。
strcpy 常规的实现代码如下(来自 OpenBSD 3.9) :char strcpychar to const char from char save to for to from 0 from to returnsave但通常, 我们的 from 都来源于用户的输入, 很可能是非常大的一个字符串,因此 strcpy 不够安全。
2. strncpy在 ANSI C 中,strcpy 的安全版本是 strncpy。
char strncpychar s1 const char s2 size_t n但 strncpy 其行为是很诡异的(不符合我们的通常习惯)。
标准规定 n 并不是 sizeofs1,而是要复制的 char 的个数。
一个最常见的问题,就是 strncpy 并不帮你保证 0 结束。
char buf8strncpy buf abcdefgh 8 看这个程序,buf 将会被 abcdefgh 填满,但却没有 0 结束符了。
另外,如果 s2 的内容比较少,而 n 又比较大的话,strncpy 将会把之间的空间都用 0 填充。
这又出现了一个效率上的问题,如下:char buf80strncpy buf abcdefgh 79 上面的 strncpy 会填写 79 个 char,而不仅仅是 abcdefgh 本身。
strncpy 的标准用法为: (手工写上 0)strncpypath src sizeofpath - 1pathsizeofpath - 1 0len strlenpath3. strlcpy// Copy src to string dst of size siz. At most siz-1 characters// will be copied. Always NUL terminates unless siz 0.// Returns strlensrc if retval siz truncation occurred.size_tstrlcpychar dst const char src size_t siz而使用 strlcpy,就不需要我们去手动负责 0 了,仅需要把 sizeofdst 告之 strlcpy 即可:strlcpypath src sizeofpathlen strlenpathif len sizeofpath printfsrc is truncated.并且 strlcpy 传回的是 strlenstr,因此我们也很方便的可以判断数据是否被截断。
一点点历史 strlcpy 并不属于 ANSI C,至今也还不是标准。
strlcpy 来源于 OpenBSD 2.4,之后很多 unix-like 系统的 libc 中都加入了 strlcpy 函数,我个人在 FreeBSD、Linux 里面都找到了 strlcpy。
(Linux 使用的是 glibc,glibc 里面有 strlcpy,则所有的 Linux 版本也都应该有 strlcpy)但 Windows 下是没有 strlcpy 的,对应的是 strcpy_s 函数///////////////////////////////////////////////////////////////////////////strncpy 原型:extern char strncpychar dest char src int n 用法:include 功能:把 src 所指由 NULL 结束的字符串的前 n 个字节复制到 dest 所指的数组中。
说明: 如果 src 的前 n 个字节不含 NULL 字符,则结果不会以 NULL 字符结束。
如果 src 的长度小于 n 个字节,则以 NULL 填充 dest 直到复制完 n 个字节。
src 和 dest 所指内存区域不可以重叠且 dest 必须有足够的空间来容纳 src 的字符串。
返回指向 dest 的指针。
举例: // strncpy.c include include main char sGolden Global View char dHello GGV Programmers char pstrdups clrscr textmode0x00 // enable 6 lines mode strncpydsstrlens printfsnd strncpypsstrlend printfsp getchar return 0 Return:return 表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值,由 return 后面的参数指定。
return 通常是必要的,因为函数调用的时候计算结果通常是通过返回值带出的。
如果函数执行不需要返回计算结果,也经常需要返回一个状态码来表示函数执行的顺利与否 , (-1 和 0 就是最常用的状态码) 主调函数可以通过返回值判断被调函数的执行情况。
在最新的 C99 标准中,只有以下两种定义方式是正确的: int main void int main int argc char argv 当然, 我们也可以做一点小小的改动。
例如:char argv 可以写成 char argv; argv 和argc 可以改成别的变量名(如 intval 和 charval) ,不过一定要符合变量的命名规则。
如果不需要从命令行中获取参数,请用 int mainvoid ;否则请用 int main int argc charargv 。
main 函数的返回值类型必须是 int ,这样返回值才能传递给程序的激活者(如操作系统) 。
C98 中定义了如下两种 main 函数的定义方式: int main int main int argc char argv int main 等同于 C99 中的 int main void ;int main int argc char argv 的用法也和C99 中定义的一样。
同样,main 函数的返回值类型也必须是 int。
如果 main 函数的末尾没写 return 语句, C98 规定编译器要自动在生成的目标文件中加入 return 0 。
同样,vc6 也不支持这个特性,但是 g3.2(Linux 下的 C 编译器)支持。
如果你想你的程序拥有很好的可移植性,请一定要用 int main 。
返回值的作用:main 函数的返回值用于说明程序的退出状态。
如果返回 0,则代表程序正常退出,否则代表程序异常退出。
在函数中,如果碰到 return 语句,那么程序就会返回调用该函数的下一条语句执行,也就是说跳出函数的执行,回到原来的地方继续执行下去。
但是如果是在主函数中碰到 return 语句,那么整个程序就会停止,退出程序的执行。
高速缓冲存储器cache定义:比主存储器体积小但速度快,用于保有从主存储器得到指令的副本——很可能在下一步为处理器所需——的专用缓冲器。
MMUMMU 是 Memory Management Unit 的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权。