‘壹’ 什么是补码加减运算溢出判别溢出有哪几种方法并我说明工作原理。
通常有三种表述方式(说法):
(1)
两个符号相同的补码数相加,如果和的符号与加数的符号相反,或两个符号相反的补码数相减,差的符号与减数的符号相同,都属于运算结果溢出。这种判别方法比较复杂,要区别加还是减两种不同运算情况,还要检查结果的符号与其中一个操作数的符号的同异,故很少使用;
(2)
两个补码数相加减时,若最高数值位向符号位送的进位值与符号位送向更高位的进位值不相同,也是运算结果溢出。
(3)
在采用双符号位(如定点小数的模4补码)运算时,若两个符号位的得值不同(01或10)则是溢出。01表明两个正数相加,结果大于机器所能表示的最大正数,称为"上溢";10表明两个负数相加,结果小于机器所能表示的最小负数,称为"下溢";双符号位的高位符号位,不管结果溢出否,均是运算结果正确的符号位,这个结论在乘法运算过程中是很有实际意义的。请注意,在采用双符号位的方案中,在寄存器和内存储器存储数据时,只需存一位符号,双符号位仅用在加法器线路部分。
再次强调,这三种不同说法是对同一个事实的略有区别的表述,实现时用到的线路可以有所区别,但问题的实质是完全一样的。
‘贰’ FreeRTOS操作系统例程:任务栈溢出检测
* 1. 学习FreeRTOS的任务栈溢出检测方法一(模拟栈溢出)。
* 2. FreeRTOS的任务栈溢出检测方法一说明:
* a. FreeRTOSConfig.h文件中配置宏定义:
* #define configCHECK_FOR_STACK_OVERFLOW 1
* b. 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。
* void vApplicationStackOverflowHook( TaskHandle_t xTask,
* signed char *pcTaskName );
* 用户可以在钩子函数里面做一些处理。本实验是在钩子函数中打印出现栈溢出的任务。
* c. 这种方法不能保证所有的栈溢出都能检测到。比如任务在执行的过程中发送过栈溢出。任务切换前
* 栈指针又恢复到了正常水平,这种情况在任务切换的时候是检测不到的。又比如任务栈溢出后,把
* 这部分栈区的数据修改了,这部分栈区的数据不重要或者暂时没有用到还好,如果是重要数据被修
* 改将直接导致系统进入硬件异常。这种情况下,栈溢出检测功能也是检测不到的。
* d. 本实验就是简单的在任务vTaskUserIF中申请过大的栈空间,模拟出一种栈溢出的情况,溢出后触
* 发钩子函数,因为我们将溢出部分的数据修改了,进而造成进入硬件异常。
#define configCHECK_FOR_STACK_OVERFLOW 1
/*
*********************************************************************************************************
* 函 数 名: StackOverflowTest
* 功能说明: 任务栈溢出测试
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void StackOverflowTest(void)
{
int16_t i;
uint8_t buf[2048];
(void)buf; /* 防止警告 */
/*
1. 为了能够模拟任务栈溢出,并触发任务栈溢出函数,这里强烈建议使用数组的时候逆着赋值。
因为对于M3和M4内核的MCU,堆栈生长方向是向下生长的满栈。即高地址是buf[2047], 低地址
是buf[0]。如果任务栈溢出了,也是从高地址buf[2047]到buf[0]的某个地址开始溢出。
因此,如果用户直接修改的是buf[0]开始的数据且这些溢出部分的数据比较重要,会直接导致
进入到硬件异常。
2. 栈溢出检测是在任务切换的时候执行的,我们这里加个延迟函数,防止修改了重要的数据导致直接
进入硬件异常。
3. 任务vTaskTaskUserIF的栈空间大小是2048字节,在此任务的入口已经申请了栈空间大小
------uint8_t ucKeyCode;
------uint8_t pcWriteBuffer[500];
这里再申请如下这么大的栈空间
-------int16_t i;
-------uint8_t buf[2048];
必定溢出。
*/
for(i = 2047; i >= 0; i--)
{
buf[i] = 0x55;
vTaskDelay(1);
}
}
/*
*********************************************************************************************************
* 函 数 名: vApplicationStackOverflowHook
* 功能说明: 栈溢出的钩子函数
* 形 参: xTask 任务句柄
* pcTaskName 任务名
* 返 回 值: 无
*********************************************************************************************************
*/
void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
{
printf("任务:%s 发现栈溢出\r\n", pcTaskName);
}
实验目的:
* 1. 学习FreeRTOS的任务栈溢出检测方法二(模拟栈溢出)。
* 2. FreeRTOS的任务栈溢出检测方法二说明:
* a. FreeRTOSConfig.h文件中配置宏定义:
* #define configCHECK_FOR_STACK_OVERFLOW 2
* b. 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。
* void vApplicationStackOverflowHook( TaskHandle_t xTask,
* signed char *pcTaskName );
* 用户可以在钩子函数里面做一些处理。本实验是在钩子函数中打印出现栈溢出的任务。
* c. 任务创建的时候将任务栈所有数据初始化为0xa5,任务切换时进行任务栈检测的时候检测末尾
* 的16个字节是否都是0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速度
* 稍慢些,但是这样就有效的避免了方法一里面的部分情况。不过依然不能保证所有的栈溢出都能检测
* 到,比如任务栈末尾的16个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检
* 测不到的。另外任务栈溢出后,任务栈末尾的16个字节没有修改,但是溢出部分的栈区的数据修改
* 了,这部分栈区的数据不重要或者暂时没有用到还好,如果是重要数据被修改将直接导致系统进入硬
* 件异常。这种情况下,栈溢出检测功能也是检测不到的。
* d. 本实验就是简单的在任务vTaskUserIF中申请过大的栈空间,模拟出一种栈溢出的情况,溢出后触
* 发钩子函数,因为我们将溢出部分的数据修改了,进而造成进入硬件异常。
#define configCHECK_FOR_STACK_OVERFLOW 2
函数内容和上面一样:
static void StackOverflowTest(void)
void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
‘叁’ 定点数加减运算的溢出判定,可以通过______和______的方法判定。
定点数加减运算的溢出判定,可以通过___单符号位判溢方法 ___和___双符号位进位判溢方法 ___的方法判定。
定点数加减
目前计算机普遍使用补码实现定点数的加减运算。
1.加减运算方法:
根据补码的设计规则,任意的绝对值相同的负数和正数,负数是正数的反码加1,所以绝对值相同的负数和正数相加,刚刚好结果就是为全0(最高位进一位,抛弃)。然后对照下补码表,可以发现基于这种设计,两数相加时可以直接将符号位也参与运算,得出的结果也包含符号位。
2.溢出判断:
(1)单符号位判溢方法
相加溢出的情况只有两种:
正数和正数相加,结果为负数,发生溢出。
负数和负数相加,结果为正数,发生溢出。
为什么正数和负数相加不会溢出呢?是因为正数和负数的最值的绝对值都是相同的,正负相加结果一定在绝对值之内。
相减只是将加数取补码再相加,所以知道相加溢出就够了。
(2)进位判溢方法(单符号位)
由补码表观察可以知道:
不溢出的情况:
一个绝对值较大的负数和绝对值较小的正数相加,最高有效位(即最高的数值位)不会发生溢出,因此符号位也没有进位。
一个绝对值较小的负数和绝对值较大的正数相加,最高有效位溢出,且使得符号位由1变10(0)进位。
溢出的情况:
上面已经知道:
正数和正数相加,结果为负数,发生溢出。→这种情况是最高有效位进位,而符号位由0变1无进位。
负数和负数相加,结果为正数,发生溢出。→这种情况是最高有效位不进位,而符号位由1变10(0)进位。
所以当最高有效位和符号位的进位不同时,就表明发生了溢出。
(3)双符号位进位判溢方法
采用双符号位(00、11)进行相加,上面已经知道:
所以当最高有效位和符号位的进位不同时,就表明发生了溢出。
→符号位进位,最高有效位不进位就变成了11+11=10(110)。此时为负溢出。
→符号位不进位,最高有效位进位就变成了00+1=01。此时为正溢出。
‘肆’ 针对定点小数加法运算,分析 产生溢出的原因,并给出两种溢出的方法
(1)产生“溢出”的原因:
当最高有效数值位的运算进位与符号位的运算进位不一致时,将产生运算“溢出”。 当最高有效位产生进位而符号位无进位时,产生上溢; 当最高有效位无进位而符号位有进位时,产生下溢。
(2)“溢出”检测方法:
为了判断“溢出”是否发生,可采用两种检测的方法。
第一种方法:采用双符号位法, 称为“变形补码”或“模4补码”,可使模2补码所能表示的数的范围扩大一倍
第二种溢出检测方法:采用“单符号位法”。当最高有效位产生进位而符号位无进位时,产生上溢;
‘伍’ 两个无符号数相乘,怎样判断是否溢出
对于2个无符号数判断溢出用进位标志CF判断
有符号的整数用OF判断
‘陆’ 在定点 运算中,为了判断溢出是否发生,可采用双符号位检测法,不论溢出与否
溢出判断,一般用双符号位进行判断:
符号位00
表示正数
11
表示负数
结果的符号位为01时,称为上溢;为10时,称为下溢
设x和y是4位的有符号数,x=7,y=-7,符号位为双符号位
用补码求x+y,x-y
[x]补+[y]补=00
111+11
001=0
0000结果不溢出
[x-y]补=[x]补+[-y]补=00
111+00
111=0
1110结果上溢出。
同理,可以判断x,y为其他位数的补码运算溢出。