类型提升&&滑动滤波&&低通滤波&&Little_endian Big_endian

【整型提升,有符号和无符号】

K&R C[比ASIC C古老]中关于整型提升(integral promotion)的定义为:

"A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion."

上面的定义归纳下来就是以下两个原则:

    1). 只要一个表达式中用到了整型值,那么类型为char、short int活整型位域(这几者带符号或无符号均可)的变量,以及枚举类型的对象,都可以被放在这个整型变量的位置。
    2). 如果1)中的变量的原始类型值域可以被int表示,那么原值被转换为int;否则的话,转为unsigned int。
    
    以上两者作为一个整体,被成为整型提升(Integral promotion)

---------

下面一个小程序,演示了c语言中类型提升(整型提升(integral promotion))带来的一个小问题

(转自http://blog.csdn.net/ubuntulover/article/details/4719977)。

//test.c

#include <stdio.h>
int array[]={23,34,45,56,67,78};
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0]))
int main()
{
    int d=-1,
        x=3;
    if(d<=TOTAL_ELEMENTS-2)
      x=array[d+1];
    printf("the value of x is %d/n",x);
    return 0;
}

编译运行,结果如下:

alei@alei-desktop:~$ gcc test.c -o test
alei@alei-desktop:~$ ./test
the value of x is 3

为什么结果是3而不是23呢?

先看ANSI C手册中的关于寻常算术转换的规定。

首先,如果一个操作书的类型是long double,那么另一个操作数也被转化为long double。其次,如果一个操作数的类型是double,那么另一个操作数也被转换为double。再次,如果其中一个操作数的类型是float,那么另一个操作数也被转换为float。否则,两个操作数进行整型提升,执行下面的规则:

如果其中一个操作数是unsigned long int,那么另一个操作数也被转换为unsigned long int。其次,如果其中一个操作数是long int, 而另一个操作数的类型是unsigned int ,如果long int 能够完整表示unsigned int 的所有值,那么unsigned int类型操作数被转换为long int,如果long int类型不能完整的表示unsigned int 的所有值,那么两个操作数都被转换为unsigned long int。再次,如果其中一个操作数的类型是long int,那么另一个操作数转换为long int。再再次,如果其中一个操作数的类型是unsigned int ,那么另一个操作数被转换为unsigned int。如果所有以上的情况都不属于,那么两个操作数都为int。

简言之,当进行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高,长度更长的防线转换,整型数如果转换为signed 不会丢失信息,就转换为signed,否则转换为unsigned。

再看上面的程序。

解释:TOTAL_ELEMENT所定义的值是unsigned int类型,因为sizeof()返回类型是无符号数。if语句在signed int和unsigned int之间测试大小关系,所以d被提升为unsigned int类型。 -1转换成unsigned int 的结果将是一个非常巨大的正整数,导致if判断为假。

  解决方法:可以修改第四行为:#define TOTAL_ELEMENTS (int)(sizeof(array)/sizeof(array[0]))

  建议:

  尽量不要在代码中使用无符号类型,以免增加不必要的复杂性。尤其是,不要仅仅因为无符号数不存在负值(如年龄、国债等)而用它来表示数量。尽量使用int那样的有符号类型,这样在涉及升级混合类型的复杂细节时,不必担心边界的情况(如-1被转化为非常大的正整数)。

  只有在使用位段和二进制掩码的时候,才可以使用无符号数。应该在表达式中使用强制类型转化,是操作数均为有符号数或者无符号数,避免编译器来选择结果的类型。

-----------------

    int d=-1,x=3;
    unsigned int cccc = 4;

    if(d <= cccc) // complier warning :always FALSE [if在signed int和unsigned int之间测试相等性,所以d被提升为unsigned int 类型的。只是表达式的值为假。]
//    if(d <= (int)cccc) // complier warning :always true
//    if(d <= 4)// complier warning :always true
    {
     x=array[d+1];
    }

-------------

#include < stdio.h>
#include < string.h>
int main ()
{
    int x = 2;
    char * str = "abcd";
    int y = (x - strlen (str) )/ 2;
    printf("% d\n",y);
}

结果应该是 -1 但是却得到:2 1 4 7 4 83 6 4 7 。为什么?因为 strlen的返回值,类型是 siz e_t,也就是 unsig n ed int ,与 int 混合计算时有符号类型被自动转换成了无符号类型,结果自然出乎意料。。。
观察编译后的代码,除法指令为 div ,意味无符号除法。
解决办法就是强制转换,变成 in t y = (int)(x - strlen (str) ) / 2 ; 强制向有符号方向转换(编译器默认正好相反),这样一来,除法指令编译成 idiv 了。
我们知道,就是同样状态的两个内存单位,用有符号处理指令im ul ,idiv 等得到的结果,与用 无符号处理指令 m ul,div 等得到
的结果,是截然不同的!所以牵扯到有符号无符号计算的问题,特别是存在讨厌的自动转换时,要倍加小心!(这里自动转换 时,无论gcc 还是 cl都不提示!!!)
为了避免这些错误,建议,凡是在运算的时候,确保你的变量都是signed

------------------------------------------------------------------------------------------------

以下答题假定int是16位,char是8位,long是32位:

unsigned char x=0xff;
~x   //结果是多少?
答:0x00,跟KEIL模拟结果一样
正确结果是(int)0xFF00;
char没有~运算能力,运算先先会被提升至int.
~x相当于~((int)x)
KEIL C51这里并没有遵守C标准。
http://www.amobbs.com/thread-4582991-1-1.html

unsigned char a=255;
unsigned char b=1;
int c=a+b;    //结果为多少?
答:0x100,跟KEIL模拟结果一样
----------------
正确。
unsigned char没有+运算能力,运算之前先提升至int
a+b相当于((int)a+(int)b)
结果是(int)0x100

unsigned int a=65535;
unsigned int b=1;
long int c=a+b;    //结果为多少?
答:0x10000,跟KEIL模拟结果不一样,KEIL里结果为 0x00000
----------------
为什么结果为0,而是不是0x10000呢?
先看a+b,
a是unsigned int,b也是unsigned int,
unsigned int与unsigned int运算不需要提升,也不需要类型转换,结果仍然是unsigned int
a+b相当于(unsigned int)(a+b)
c=a+b
相当于c=(long)((unsigned int)(a+b))
结果当然为0


int a,b;
unsigned char i=1; 
signed char j=-1;
unsigned int k=1; 
signed int l=-1;
a=(i>j);     //结果为多少?
b=(k>l);    //结果为多少?
这个没研究,因为我不会这么写程序
-----------------------------
这里要强调,char不仅没有+-*/ & | ~运算,< > >= <=也运算也没有。
要进行比较运算,也必须要首先提升。

(i>j)
i是unsigned char,j是signed char
比较前先提升至int
(i>j)相当于((int)i>(int)j,结果为真。

而(k<l)
k是unsigned int,l是signed int
unsigned int与signed int进行运算,signed int首先转换成unsigned int
(k<l) 相当于 (k<(unsigned int)l),结果为假。

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

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

滑动滤波】

if(idx < (BUFFER_SIZE - 1))

{

    idx ++;

}

else

{

    idx = 0;

}

buffer[idx idx ] = new_data;// new_data输入,buffer[BUFFER_SIZE  ]为全局数组,by 282280072

 

int i = 0;

int sum = 0;

 

for(i=0;i< BUFFER_SIZE ;i++)

{

    sum  += buffer[i] 

}

 

out = sum  /BUFFER_SIZE ;

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

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

低通滤波】

关于低通滤波

正确的写法:

float out = 0;

int in = 256;

while(1)

{

out = 0.9887*out + (1 - 0.9887)*in;

}

out最终为255.9993;

-----------------

错误的写法:

int out = 0;

int in = 256;

while(1)

{

out = (4050*out + (46)*in)>>12;

}

out最终为167; 由于右移而导致的误差。

------------------------

正确的写法:

int out = 0;

int sum= 0;

int in = 1234;

int temp;

while(1)

{

temp = in - out;

sum = sum + temp;

out =sum>>5;// 更改5这个值,可以修改滤波的速度,

}

out最终为1234;只要in != out,sum就一直累加

 

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

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

 

Little_endian  Big_endian

 试题1:请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1
解答:

 

 

 

 

posted on 2013-07-01 21:39  yq09  阅读(275)  评论(0编辑  收藏  举报