搜索
bottom↓
回复: 42

马老师,你好,能不能帮我分析一下两个C语言语法结构问题!

[复制链接]

出0入0汤圆

发表于 2007-5-11 13:47:14 | 显示全部楼层 |阅读模式
uchar SendControlInfo[11]; //均浮充,限流信息

  extern bit JunChongState;     //均充标志位

  SendControlInfo[3]=((uchar*)&JunChongVSet)[0];

这是什么结构呀,马老师,看不明白!

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2007-5-12 04:34:33 | 显示全部楼层
试试吧



uchar SendControlInfo[11]; //均浮充,限流信息

uchar 应该是 unsigned char 的再定义。查一下,在前面或一般在include的globle.h文件中有这样的定义#define uchar unsigned char。所以这是定义一个11个元素的数组。类型为无符号字节型。(在单片机的C中,最好不要简单认为是字符型,它经常不是“字符”,而是0-255的数)



extern bit JunChongState;     //均充标志位

这是声明有一个位(1bit)变量JunChongState,该变量在其它程序中或在h文件中定义的。在标准C里,没有位变量的,这是有些单片机的C语言(如CVAVR)扩展的变量类型。该类型的变量通常只能是全局变量。



SendControlInfo[3]=((uchar*)&JunChongVSet)[0];

这个稍微复杂些了,举个简单的例子解释:JunChongVSet是一个long型变量,占4个字节(根据语言环境所定)。&JunChongVSet得到该变量的指针,它是一个指向long型变量的指针。(uchar*)&JunChongVSet把这个指针强行转换成一个指向字节的指针。此时4个字节的变量JunChongVSet相当一个4个元素的字节型数组,(uchar*)&JunChongVSet相当于这个数组的名。

那么SendControlInfo[3]=((uchar*)&JunChongVSet)[0]实际上就是将JunChongVSet的第一个字节的值赋给SendControlInfo[3]。SendControlInfo是一个字节型数组。

实际上JunChongVSet可以为任何类型的变量(不能是BIT变量),如一个结构变量。



我在这种情况时,通常使用共同体结构,将JunChongVSet和一个uchar数组定义使用共同的存储空间单元。



以上解释请参考。

出0入0汤圆

 楼主| 发表于 2007-5-12 13:25:43 | 显示全部楼层
谢谢马老师的精彩点评,使我收获很多,

但我还是有一点不太明白,你说:“将JunChongVSet和一个uchar数组定义使用共同的存储空间单元”我认为:SendControlInfo[3]=((uchar*)&JunChongVSet)[0]这只是一个赋值语句,他们存储空间地址,是不一样的!

出0入0汤圆

发表于 2007-5-12 15:47:48 | 显示全部楼层
在你所给出的问题中,SendControlInfo[3]和JunChongVSet他们存储空间地址是不一样的。



我根据你的语句,已经估计和判断到编写人员为什么要使用这样的语句,以及实际想法了。所以我讲我要碰到这种情况时,回采用另外的定义方式,将JunChongVSet和一个uchar数组定义使用共同的存储空间单元,这样你所给出的那么复杂的赋值语句根本就不需要了。而且还节省了内存单元,这是一种更好的设计方法。



如果你还不理解的话,说明你还不没有彻底理解你第3条语句为什么要这样设计。



举实际例子说明吧。

假如在你的系统中有一个结构变量a,内含设备的型号(8字节字符)、库存量(2字节整形数),共10个字节的长度。系统需要修改、查看设备的型号和库存量时,当然使用这个结构变量a非常方便。但如果需要将这个结构变量的值通过RS232发出去的话,需要把它拆成10个字节一个一个的发。



采用你的例子的方法,就是另外定义一个10个字节的数组b,通过“难懂”的赋值语句,把结构变量的值一个字节一个字节的读到字节数组中,然后按字节发送数组b。



而我也会定义一个10字节的数组c,但它与结构变量a共用一个存储空间(共同体结构),发送时不需要赋值了,只要按字节发送数组c就可以了。这样设计,不但节约内存空间,也节约程序空间,同时效率也高。一石三鸟。

出0入0汤圆

发表于 2007-5-12 16:08:26 | 显示全部楼层
回到我20年前的教学内容了。我不仅曾经教过BASIC、FOTRON、PASIC、C、FOXPRO、HTML语言+ASP技术、8086汇编、Z80汇编,而且自己用过的还要多,如VB、VC、6502汇编、51汇编。



看样子要再开一个C语言深入应用的栏目了。建议阿莫找个C语言的好手做主持,太多的所谓会使用C的要学习AVR,实际上是不会真正使用C的,这些跟AVR本身是无关的。



顺便问一下现在正在选修我的课的学生们,你们真正会C语言的程序设计吗?学习是为了考试还是为了使用?面对今天我们这样的教学体制、理念和习惯,你们应该如何调整自己的学习态度和方法?

出0入0汤圆

 楼主| 发表于 2007-5-13 21:52:36 | 显示全部楼层
马老师,你分析的太精彩了,我明白了



而且你还从作者的一个简单的语句分析到作者的目的和思想,我看了主程序,的确像马老师所说,精彩,太精彩了!马老师这一点拨,受益匪浅!

谢谢马老师!

出0入0汤圆

 楼主| 发表于 2007-5-13 22:02:42 | 显示全部楼层
马老师,我也同意你的建议--开一个C语言深入应用的栏目。



我们太需要这样一个栏目了,我们都有很多C语言的疑惑需要解决,C语言的精华很多人并不理解!

马老师不就是个C语言的高手吗?还用得着别人, 我建议就有马老师主持这个栏目!

出0入0汤圆

 楼主| 发表于 2007-5-13 22:33:02 | 显示全部楼层
顺便在问马老师两个C 语言的问题,C语言定义一个普通变量时,在没有赋初值时候,在编译时候分配内存吗? 指针变量呢?

内部变量赋值之后是不是也不分配内存?



在函数外定义的变量,默认为Extern变量,但是书上说用Extern声明的变量,在定义时候是不允许赋值的,但是我不明白为什么不允许,那为什么在函数外定义变量时候能赋初值?

  



外部静态变量(在函数外用Satic声明),是不是在所有有效函数外都不会改变,那还有什么意义?

出0入0汤圆

发表于 2007-5-13 23:36:15 | 显示全部楼层
建议你先找本C的书,把变量的作用域、生命周期、内存分配等基本的概念弄清楚,然后尝试自己分析,得到结论。



基本概念不清楚的话,书上的解释你就看不懂了。

出0入0汤圆

 楼主| 发表于 2007-5-14 12:22:38 | 显示全部楼层
我看了很多本书,都找不到答案,也是因为看了这些书才产生这么多问题的,



比如:C语言定义一个普通变量时,在没有赋初值时候,在编译时候分配内存吗?

  指针变量呢?



   内部变量赋值之后是不是也不分配内存?

   找不到答案!

出0入0汤圆

发表于 2007-5-16 13:36:41 | 显示全部楼层
不管是什么类型的变量,有没有赋初值,只要定义了,编译的时候都会给它分配内存.

出0入0汤圆

发表于 2007-5-17 02:03:51 | 显示全部楼层
首先需要把基本的定义进行统一。

一般的讲,在一个C文件中,凡是在函数外部定义的变量称为全局变量,其作用域为文件本身,在本文件中的出现的任何函数中可以使用。



在一个函数中定义的变量称为局部变量,其作用域函数本身。一旦函数执行完成,该变量不存在。



通常C编译器会开辟两个数据空间,一个是公共的数据空间,一个是临时数据空间。凡是全局变量,不管是什么类型的变量,有没有赋初值,只要定义了,编译的时候都会给它在公共数据区分配内存。而对于局部变量处理,各个编译器可能有些不同,通常是在函数执行的时候进行分配,分配在临时数据空间中,函数执行完,变量也就不存在了(其实,变量还在临时空间中,只是下一个函数执行时,可能将该空间分配给另外一个局部变量了)。



当你的系统程序由2个以上的C文件构成时,如果在一个C文件中的函数要使用另外一个C文件中定义的全局变量,不能进行重复定义,需要使用Extern进行声明(注意,不是定义,所以不能赋值)。这样,编译器在编译过程中不会对该变量进行地址分配,只是等到连接时,将该变量的地址对应到在另外一个C文件定义的该变量(它要分配地址的)的地址上。这样一个全局变量就能在整个系统中使用了。



在函数中的定义的局部变量,如果具备static的属性(该变量在仅本函数中使用,但其值要保持上次使用的结果,不能丢失和改变),编译器通常也会把它作为全局变量处理(具备全局变量的性质了),编译时将其分配在公共数据区中。但它与真正的全局变量还是不同的,还是只能在定义该变量的函数中使用。



对于硬件系统的程序设计人员来讲,采用C语言编写单片机的系统程序是非常方便,有很多的优点。好象与使用汇编相比,对程序员的水平要求降低了,其实这是一种相当错误的认识。



采用C语言编写单片机系统程序,实际上对程序员的要求是更高了。尤其在进行系统调试过程中,可能有时你必须去看生成的汇编(当然不是全部看)代码,这就是说,你必须熟悉汇编。同时还要对你所使用的C编译器的内部结构有相当的了解和熟悉。尤其是开发单片机的C语言平台,对相同的芯片每一平台处理的方式可能都不一样。例如,开发AVR的GCC、IAR、ICC、CVAVR,都是使用C,但有比较大的区别。所以,光一本C的教科书不够,因为它介绍的是标准的东西,更多的是侧重如何使用。在此基础上,你还应该将你使用的C平台的手册更加仔仔细细的弄明白才行。当然,这些都是建立在你具备了比较扎实的基础上。

出0入0汤圆

 楼主| 发表于 2007-5-18 19:59:53 | 显示全部楼层
谢谢马老师,那么晚了还没休息,辛苦了!

应该注意身体!

出0入0汤圆

 楼主| 发表于 2007-5-18 20:11:40 | 显示全部楼层
马老师分析的很正确,我在补充一下,这是我最近总结出来的,希望能和大家分享!



  对于局部变量,分配局部变量的策略一般有两种,一种是把局部变量分配到堆栈中,另一种是把局部变量分配到内存中的固定地址;第一种方法在编译后变量的地址是不知道的,第二种方法在编译时指定了变量的地址。

第一种:方法函数可以嵌套调用,也就是可重入函数。

第二种方法:使用这种方法,编译器会分析整个程序的调用关系,并把没有调用关系的函数的局部变量分配到同样的内存地址,请看下例:



void funcA()

{

  int XA, YA;

  ....

}



void funcB()

{

  int XB, YB;

  ....

}



void funcC()

{

  int XC, YC;

  ....

  funcB();

  ....

}



main()

{

  ....

  funcA();

  funcB();

  ....

}



funcA与funcB()之间没有调用关系,所以XA与XB被分配到同一个地址、YA与YB被分配到同一个地址;而funcC与funcB有调用关系,所以XC与YC被分配到另外的地址。



    有些指令系统(尤其是8位单片机)中直接访问内存的指令比访问堆栈的指令有较高的效率(速度快、代码短),用这种分配方式可以达到更高的程序效率;另为访问堆栈的指令通常使用索引寄存器,在寄存器数量缺乏时,这种方法十分有效。但这种分配方式不适合用于有嵌套的程序。

具体按哪种方法,和编译器有关系!



   声明为Extern的全局变量是表示该变量已经在其他C文件中定义过了,请分清“定义”和“声明”的区别;一个项目中可以有无数个C文件,一个变量可以在不同的C文件中声明无数次,但这个变量只能在所有C文件中被定义一次;因为变量的定义是要分配内存地址的,两次用同一个名字定义一个变量意味着为这个变量分配两个不同的地址,这是不允许的。

    定义变量时是可以赋初值的,但声明变量时不允许赋初值;这里同样要分清“定义”和“声明”的区别。



  这是我最近总结出来的,也请教了好多人!

请大家参考!

出0入0汤圆

发表于 2007-5-18 22:39:33 | 显示全部楼层
LZ能给出这么深入的说明,看来是来者不善也。



估计LZ提出的问题不是自己不知道,而是要考考我。那么我的回答得几分,能及格吧:)

出0入0汤圆

 楼主| 发表于 2007-5-19 12:28:55 | 显示全部楼层
马老师,你好,我哪有水平考你呀,我上面已经声明了,这是我最近才总结出来的,也是听别人指点的,有了自己的东西就想和别人分享,这不就是论坛的精神之所在吗?

   

   自从我有了这个问题后,我就想尽一切办法区寻求答案,因为我是个心里不能放问题的人,遇到问题一定要解决,追求其根本原理,不然睡觉也不安稳的!

   

   我每次遇到问题的时候,首先想到的就是马老师你了,原因有四点:

   第一:马老师水平高,经验丰富。

   第二:马老师是一位非常优秀的老师,一切为学生着想,一切为传授知识为目的!

   第三:马老师责任心非常强,只要有人提出问题,无论他有多忙,自己有多累;无论已经工作了多长时间,也要把学生提出的问题解决掉。

   第四:马老师教学经验丰富,理解提问者的心思,回答到位,认真仔细,从不马虎!是一为难得的好老师!

  上面四点都是我的亲身所感受,像这样的好老师我哪里敢考,心里只有尊敬和赞美,在这样一个物质追求很高的社会里面这样的老师不多了!

出0入0汤圆

发表于 2007-5-19 15:24:46 | 显示全部楼层
哈哈!但考无妨啊!



这样的老师也不怕考啊!



再者考试是一种检验方式,目的是共同进步哦!!

出0入0汤圆

发表于 2007-5-19 15:33:48 | 显示全部楼层
过了。我没有那么高的水平,觉悟也不高。



只是本学期教的学生比较多,由于特殊的原因(新校区太远)没有更多的机会同学生交流,所以本意是借用本讨论组(感谢阿莫)回答一些学生的问题,以感谢同学对我的大力支持(我听说学生写了联名信到学校要求我上课,同时本学期有那么多的学生选修我的课,非常感动)。网上都是使用虚名制的,可我是实名制的,所以你如果是我教的学生,那么我是应该这样做的,同时还要表扬你。如果你不是我的学生,那你就“赚”了,等什么时间有机会,请我一顿表示感谢就行了:)



我真心希望我所教的学生能够“青出于蓝而胜于蓝”,掌握更好的技术,具备更多的本事(不仅仅是专业方面的)。那时不是考老师的问题了,等你发达了,我退休后还想到你那里打打工,看看门呐。

出0入0汤圆

 楼主| 发表于 2007-5-19 16:08:04 | 显示全部楼层
^_^...马老师我们都会努力的!

出0入0汤圆

 楼主| 发表于 2007-5-19 16:10:00 | 显示全部楼层
马老师,刚才看了看你以前的帖子,看到这样一句:

“由于AVR片内提供比较多的RAM,所以目前所有AVR的C语言平台所建立的函数都是可重入的,与51的keil不同”



这是不是和我上面总结的有点矛盾!

出0入0汤圆

发表于 2007-5-19 19:25:02 | 显示全部楼层
不管是使用那种方式给临时变量分配内存都要占用RAM。AVR和51的结构不同(实际上有质的飞跃,只是大部分的工程师还认识不到这点),不仅片内集成了更多的RAM,而且它的数据空间(不管内部还是外部)是一个线性连续的空间(51的硬件堆栈只能在内部RAM中建立)。这样的设计就是考虑到能够更好的适应C语言的特点,所以目前针对AVR的C平台的函数都是可重入的,不象KEIL。



你上面的分析没有错,只是有一定的局限性,因为可能你了解的主要是建立在针对51这样的架构上的平台。



针对单片机开发的C平台实际上都不是标准的C平台了,需要根据具体的芯片采用一些专门的技术来实现C的一些特点。对于这些我没有再深入下去,因为我所侧重的是应用。你可以看一下,例如ICCAVR的帮助,在“Program and Data Memory Usage”这节里有对内存分配和使用情况的介绍。

出0入0汤圆

 楼主| 发表于 2007-5-19 21:15:46 | 显示全部楼层
马老师,KEIL的局部变量也是放在RAM中的呀,堆栈也是在内部RAM中的,我感觉你那句话应该是这样比较合适

    "由于AVR片内提供比较多的寄存器,所以目前所有AVR的C语言平台所建立的函数都是可重入的,与51的keil不同”

  是寄存器,而不是RAM!

  

可重入函数和一般的函数都是要占用内存--也就是RAM,不是因为RAM多就要是可重入的了!

不知道我所的对不对?请马老师指教!

出0入0汤圆

发表于 2007-5-20 00:59:54 | 显示全部楼层
典型的可重入函数应用的例子是实现递归了,就是函数自己调用自己。



在这种应用中,除了每次调用都必须再次的给变量分配内存,还要使用堆栈进行断点和现场的保护。假如一个可重入函数中定义了一个char型变量,那么当函数自己调用自己N次时,需要分配N个内存单元给N个变量,同时更可怕的是需要N倍的堆栈空间进行断点和现场的保护,没有大容量的RAM支持是不行的。



在KEIL中是可以定义可重入函数的,但必须加上特殊的说明。其原因就是由于51结构的限制,所以按常规定义的函数是不可重入的,主要就是为了节省内存。

出0入0汤圆

 楼主| 发表于 2007-5-20 12:45:26 | 显示全部楼层
多谢马老师指教!我明白了!

出0入0汤圆

 楼主| 发表于 2007-5-21 13:14:19 | 显示全部楼层
马老师,我的问题又来了,AVR函数都是可重入的,但我不知道它在编译的时候是怎么给

它的局部变量分配地址的,是分配到堆栈中还是分配到内存的固定地址处?



若分配到内存中的固定地址,那它是怎么实现嵌套调用的呢?

出0入0汤圆

 楼主| 发表于 2007-5-21 13:15:00 | 显示全部楼层
马老师,我的问题又来了,AVR函数都是可重入的,但我不知道它在编译的时候是怎么给

它的局部变量分配地址的,是分配到堆栈中还是分配到内存的固定地址处?



若分配到内存中的固定地址,那它是怎么实现嵌套调用的呢?

出0入0汤圆

 楼主| 发表于 2007-5-21 13:18:52 | 显示全部楼层
还有一个问题就是,在嵌入式操作系统中,在内存不足的时候,要涉及到临界区,

我不知道这个“临界区”是什么概念?

出0入0汤圆

发表于 2007-5-21 20:40:36 | 显示全部楼层
这些问题已经不属于如何使用C语言的范围了,属于更深层次的问题。你可以先看一下,例如ICCAVR的帮助,在“Program and Data Memory Usage”这节里有对内存分配和使用情况的介绍。

出0入0汤圆

 楼主| 发表于 2007-5-22 15:48:55 | 显示全部楼层
多谢马老师,那“临界区”是什么概念?

出0入0汤圆

发表于 2007-5-22 18:43:14 | 显示全部楼层
不知道你是从那本书中看到的这个概念的描述,还是自己看了一些书把有些概念混在一起了。希望你能给出更完整的问题描述。



“临界”来源于英文为critical,在中文的意思有“临界、处于转变状态的、关键性的、危险的、苛刻的”等多种。在许多英文的计算机软件、系统等资料,经常使用这个词,中文翻译没有比较准确的词与其对应,一般使用“临界”。



我的体会是,临界有“敏感”和“面临冲突”的含义在里面。当你看到某个变量为“临界变量”时,说明对该变量的操作要当心,可能你在操作的时候,还会发生其它的操作。如某个全局变量在一个中断服务中要改变它的值,那么在其它程序中对它操作就要当心。考虑会产生你没操作完,中断来了,也对它操作,这样两个操作就有可能发生冲突了。这样的变量就是“临界”变量。如果你用CVAVR产生一个USART的程序,你就能看到对临界变量的处理方式了(通常采用关中断、处理、在开中断的方法)。



在嵌入式操作系统中,每个系统对内存的管理方式不同。但一般要把内存分成几段使用,如一段为硬件堆栈、一段为软件堆栈、一段为公共数据区等等。这些段的空间要予留大小的。当RAM比较少的话,每个段的空间就不能太大。我们假定予留100个字节为硬件堆栈的大小,地址为1000-901(堆栈向小地址发展),那么从890-791可以作为软件堆栈的空间。在891-900有10个字节其什么作用呢?可以起到一个安全缓冲的作用,因为当硬件堆栈溢出到901以下时,还有10个字节的缓冲,还没有将软件堆栈冲掉。但堆栈指针到了891-900的区域就危险了,在长下去就要冲到软件堆栈了。因此,这10个字节的区域可以称为“临界区”,你可以使用这个区内的存储器,但面临着极大的危险。如果程序在运行中,有使用了临界区的现象,说明内存的容量可能不足,或分配的不合理了。



有些操作系统提供对临界区进行检验的任务或函数,在调试中,可以通过它了解临界区是否被使用过,一旦被使用过,哪怕系统没有崩溃,也知道现有的内存容量可能对你整个系统的运行不太够用,需要进行调整了。

出0入0汤圆

 楼主| 发表于 2007-5-24 13:52:42 | 显示全部楼层
马老师你好

我在嵌入式实时操作系统 Small RTOS51原理及应用上,看到的,但是它并没有描述“临界区”是什么概念,只有这么一句话:

“代码的临界区也称作临界区。该区代码在处理时是不可分割的。运行这些代码不允许被打断。一旦这部分代码开始执行,则不允许任何中断打入(这不是绝对的,如果中断不调用任何包含临界区的代码,也不访问任何临界区使用的共享资源,则这个中断可能可以执行)。为了确保临界区代码的执行,在进入临界区之前要关中断,而临界区代码执行完成以后要立即开中断。”

这个临界区,我还是不理解,它里面到底放的什么东西?

出0入0汤圆

发表于 2007-5-24 21:56:59 | 显示全部楼层
SendControlInfo[3]=((uchar*)&JunChongVSet)[0];

等同于

SendControlInfo[3]=*((uchar*)&JunChongVSet);

出0入0汤圆

发表于 2007-5-24 22:11:03 | 显示全部楼层
马老师不在,我看了,随便说几句,仅为笑话,临界区是一个操作共享资源的一段代码,这个共享资源只能一次被一个访问,在访问过程中,不允许被打断,因为如果打断,可能共享资源被写赃,

在WIN32中对于临界区的技巧有MUTEX EVENT CriticalSection 等操作,而单片机中可以通过关全局中断允许,防止被其他中断断掉.

下面一个例子共享的变量为i,code_seg1,code_seg2为临界区.





int i;



code_seg1

i=1;

i++;  

out_put(i);



code_seg2;

  i++;

  i++;

  out_put(i);



  共同操作一个i变量,不同的断的次序导致i结果不同

出0入0汤圆

发表于 2007-5-24 22:43:22 | 显示全部楼层
实际上我已经解释了这种情况:



============================================================================

临界有“敏感”和“面临冲突”的含义在里面。

当你看到某个变量为“临界变量”时,说明对该变量的操作要当心,可能你在操作的时候,还会发生其它的操作。如某个全局变量在一个中断服务中要改变它的值,那么在其它程序中对它操作就要当心。考虑会产生你没操作完,中断来了,也对它操作,这样两个操作就有可能发生冲突了。这样的变量就是“临界”变量。如果你用CVAVR产生一个USART的程序,你就能看到对临界变量的处理方式了(通常采用关中断、处理、在开中断的方法)。

=============================================================================



以上我的例子里对“临界变量”(也就是所谓的共享资源)操作就是简要说明这个问题的。



如果在一段代码中需要对这个“临界变量”操作(不是中断服务的代码),那么这段代码就是“临界代码”,从这段代码的开始到代码的结束称为“临界区”,表示这个区中的代码一旦开始执行就不能被打断,必须完整的执行,保证对临界变量的操作完整和临界变量的完整可靠。



这里的打断通常指被中断打断,因为中断是随机的。被中断打断后,除了可能在中断服务中又会对临界变量操作发生冲突外,另外在操作系统中,中断返回后首先面临着任务的切换。如果一个更高级的任务在等待的,将切换到另外的任务执行了,这个新任务的执行说不定也会对临界变量操作,又要发生冲突了。

出0入0汤圆

 楼主| 发表于 2007-5-25 15:23:11 | 显示全部楼层
多谢马老老师的细心解答!

========================================

在嵌入式操作系统中,每个系统对内存的管理方式不同。但一般要把内存分成几段使用,如一段为硬件堆栈、一段为软件堆栈、一段为公共数据区等等。这些段的空间要予留大小的。当RAM比较少的话,每个段的空间就不能太大。我们假定予留100个字节为硬件堆栈的大小,地址为1000-901(堆栈向小地址发展),那么从890-791可以作为软件堆栈的空间。在891-900有10个字节其什么作用呢?可以起到一个安全缓冲的作用,因为当硬件堆栈溢出到901以下时,还有10个字节的缓冲,还没有将软件堆栈冲掉。但堆栈指针到了891-900的区域就危险了,在长下去就要冲到软件堆栈了。因此,这10个字节的区域可以称为“临界区”,你可以使用这个区内的存储器,但面临着极大的危险。如果程序在运行中,有使用了临界区的现象,说明内存的容量可能不足,或分配的不合理了。

========================================



   

但是这段话和你上面说的好像没什么联系了吧!

出0入0汤圆

 楼主| 发表于 2007-5-25 15:30:55 | 显示全部楼层
马老师我 还有一个问题:AVR一般要把内存分成几段使用,其中有一段为公共数据区,

但是我不知道这段数据区时放什么数据的?

出0入0汤圆

发表于 2007-5-25 16:53:23 | 显示全部楼层
1.临界的含义知道了,那么我提的这些都属于“临界”的概念,临界变量、临界代码段(区),以及临界数据区等。看不同的环境如何分配和处理,可能会出现这样的定义等。



2.AVR不会将内存分成几段的,主要是你使用的C语言或操作系统它们是如何管理和分配内存的。我没有对所使用的开发平台进行过深入的了解,所以不能回答你。



3.涉及到的这些问题都属于计算机专业范畴。如果你要深入的学习,应该先学习类似“编译原理”、“操作系统”等课程,然后才是对具体软件和系统了解。这些知识相对电子工程专业的就比较深了,因为缺少这方面的基础学习。



4.我已经提供你ICCAVR的帮助,这里面有该系统对内存的分配和使用介绍。如果你使用CVAVR,那么在它的帮助中也有介绍(SRAM Memory Organization)。每个环境都可能有区别,你自己看吧。

出0入0汤圆

 楼主| 发表于 2007-5-26 20:26:26 | 显示全部楼层
多谢马老师!

出0入0汤圆

 楼主| 发表于 2007-7-17 17:35:00 | 显示全部楼层
马老师你好,还有个问题要问你!也是关于C语言的:

  

    outv=100

    outv=outv*0.5264

    请问马老师,最后outv变成实型了吗?

出0入0汤圆

 楼主| 发表于 2007-7-19 09:08:28 | 显示全部楼层
补充一下,有点漏洞!



  int outv=100

出0入0汤圆

 楼主| 发表于 2007-7-19 10:30:06 | 显示全部楼层
马老师,我现在知道outv还是整型变量!蛋我还有个问题:

    int outv=100

    outv=outv*0.5264

    outv本是整型变量,而outv*0.5264一定是个实型数据,那把它赋给outv后,它后面的小数怎么处理,是全部舍弃后面的小数,还是四舍五入到整数部分呢?

出0入0汤圆

发表于 2007-8-10 15:07:55 | 显示全部楼层
对於 SendControlInfo[3]=((uchar*)&JunChongVSet)[0]; 这条指令只是一种赋值语句!这点我想没人反对吧,而对於马老师所说估计编写作者的用法跟这样编写的目的,这个我想(只是我想)它的目的并不一定是老师所说的同共体结构来把它们分配到相同的空间吧.



(要是作者真的想要把它写成像马老师所说的,那马老师说法就成立了)



在赋值语句里等号前的是变量,我想大家都知名变量是用来干什麽用的

出0入0汤圆

发表于 2007-8-10 16:30:08 | 显示全部楼层
SendControlInfo[3]=((uchar*)&JunChongVSet)[0]; 这条指令是一种赋值语句。本身没问题。



而且它也没用共同体结构,我是讲我在这种情况下可能会用共同体,效率高,至少上面的语句可以省掉了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 02:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表