china_china 发表于 2008-5-20 17:27:04

在winAVR编译器中,char与signed char是不一样的,你知道吗?

一直以来,总认为unsigned 与 signed的区别就是一个有符号和无符号,是一个取值的范围不同 。
char和signed   char都是一样的范围是[-128,127]
unsigned   char的范围是

今天我在一个项目中,有一个数制的转换,是从unsigned char强制转换成signed char,顺手将signed char直接定义成char。噩梦从此开始。
运行的参数总是不对,因为程序比较大,还有PID处理,以前没有搞过的,个人认为是其它部分程序问题,根本就没有怀疑signed与unsigned,搞了一天,快让我崩溃了...

这样看来,char是否有符号是依赖于编译器的。我这判断对吗?

china_china 发表于 2008-5-20 17:34:41

在网上查了一下:char 到底是指 unsigned char 还是指 signed char,这确是由编译器决定的。

这样看来,winAVR中的char是指的unsigned char。

mored 发表于 2008-5-20 17:43:58

是。
icc avr好像可以设置

yyccaa 发表于 2008-5-20 17:46:27

c标准没有定义char必须是有符号的,所以是否有符号取决于编译器编译时你设的参数。
无符号运算往往比有符号运算生成的代码更小,所以makefile/avrstudio工程里可能默认设置char为无符号。
winavr有2个参数-funsigned-char和-fsigned-char,选择其中之一决定了char的符号。
谭浩强的那本c入门对c标准的解释有很多遗漏之处(有点害人,导致很多人对c标准了解不够),要以c标准的官方文档为准。

ATmega32 发表于 2008-5-20 18:42:52

老问题了
char可以是signed,也可以是unsigned.

china_china 发表于 2008-5-22 15:16:28

今天下午突想,int类型是否也是同样情况?其它的各种数据呢?

看来有时间要翻下标准C的文档。不知高手有没有比较好的C标准文档推荐,3Q.

ATmega32 发表于 2008-5-22 15:30:13

http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_290124.JPG
(原文件名:Image0022.JPG)

china_china 发表于 2008-5-22 15:43:20

我发现ATmega32大侠对C是相当精通,人也很热心。谢谢

从网上拉了一篇相关的文章:

11. 基本数据类型:整型(中)

来源:蚂蚁的 C/C++ 标准编程 作者:antigloss 等级:精品
发布于2005-10-22 18:49 被读5882次 【字体:大 中 小】

Antigloss 最后修改于 2006-12-23

1. 其它整数类型

    int 是 C 语言的基本整数类型,可以满足我们处理一般数据的需求。C 语言还提供了四个可以修饰 int 的关键字:short、long、signed,以及 unsigned。利用这四个关键字,C 语言标准定义了以下整数类型:

      1) short int(可简写为 short),和 int 一样,也是有符号整数
      2) long int(简写:long),有符号整数
      3) long long int(简写:long long),C99 标准添加的类型,
         有符号整数
      4) unsigned int(简写:unsigned),无符号整数,不能表示负数
      5) unsigned long int(简写:unsigned long),无符号整数,
         不能表示负数
      6) unsigned short int(简写:unsigned short),无符号整数,
         不能表示负数
      7) unsigned long long int(简写:unsigned long long),
         C99 添加的类型,无符号整数
      8) 所有没有标明 unsigned 的整数类型默认都是有符号整数。
         在这些整数类型前面加上 signed 可以使读者更清楚地知道
         这些是有符号整数,尽管有没有 signed 都表示有符号整数。
         例如:signed int 等同于 int 。

    一般我们把 short 称为短整型,把 long 称为长整型,把 long long 称为超长整型,把 int 称为整型。unsigned 打头的那些整数类型统称为无符号整型。例如:我们称 unsigned short 为无符号短整型。以此类推。


2. 声明方式

    这些整数类型的声明方式与 int 类型的声明方式一样。例如:

      long int estine;
      long johns;
      short int erns;
      short ribs;
      unsigned int s_count;
      unsigned players;
      unsigned long headcount;
      unsigned short yesvotes;
      long long ago;/* C99 特有 */
      unsigned long long ego;/* C99 特有 */

如果您的编译器不支持 C99 标准,那就不能使用 long long 和 unsigned long long。


3. 取值范围(表示范围)

    标准也规定了这些整数类型的最小取值范围。short 的最小表示范围和 int 一样,都是
-32767 到 32767 。也就是 -(2^15 - 1)到(2^15 - 1)。其中,2^15表示 2 的 15 次方。类似地,2 的 20 次方记作 2^20 ,以此类推。注意:C 语言中 2^15 并不表示 2 的 15 次方,为了书写方便,我们姑且这么表示。long 的最小取值范围是 -2147483647 到 2147483647 。也就是 -(2^31 - 1) 到 (2^31 - 1) 。unsigned short的最小表示范围和unsigned int 一样,都是 0 到 65535(2^16 - 1)。unsigned long 的最小取值范围是 0 到 4294967295(2^32 - 1)。long long的最小取值范围是 -9223372036854775807(-(2^63 - 1))到 9223372036854775807(2^63 - 1);unsigned long long 是 0 到 18446744073709551615(2^64 - 1)。

    标准规定,int 的表示范围不能小于 short 的表示范围,long 的表示范围不能小于 int 的表示范围。这就是说 short 型变量占用的空间可能比 int 型变量少,而 long 型变量占用的空间可能比 int 型变量多。16 位(bit)的计算机中,int 和 short 一般都是 16 位,而 long 是 32位;32位的计算机中,short一般是 16 位,而long和int是 32位。TC2(16位的编译器)中,int是16位的;而 Dev-C++(32 位的编译器)中,int 是 32 位的。

    使用 unsigned int 声明的变量只能表示非负整数(0 和正整数)。如果 int 是 16 位的话,那么 unsigned int 的表示范围是 0 到 65535(2^16 - 1)。这是因为 unsigned 不需要符号位,可以把 16 个位全都用于表示整数。而 int 需要一个位作为符号位,用于表示正负,只有 15 个位用于表示整数。

    目前,long long 一般 64 位,long 是 32 位,short 是 16 位,而 int 或者 16 位,或者 32 位。具体某个编译器到底使用多少位来表示这些类型,我们可以用运算符 sizeof 来获取。例如:

          printf( "%lu\n", (unsigned long)sizeof(int) * 8 );/* 输出 int 的位数 */
          printf( "%zu\n", sizeof(short) * 8 );/* 输出 short 的位数 */

    sizeof 运算符返回其操作数占用空间的大小,以字节(Byte)为单位。注意,C 定义字节的大小为 char 类型的大小。char 通常是 8 位(bit)的,当然也可以更大。这里我们假设 char 是 8 位的。点击查看 char 类型详细介绍

    sizeof 的用法我们以后会讲到,现在只要有个印象就好了。第二句中的 %zu 是 C99 特有的,如果您的编译器不支持 C99(准确地说,应该是如果您的编译器使用的库函数不支持 C99),运行结果将会出错。


4. 整数类型的选择

    如果您要处理的只是非负整数,那么应该优先使用 unsigned 打头的那些整数类型。如果您要处理的整数超出了 int 所能表示的范围,并且您的编译器中,long 的表示范围比 int 大,那就使用 long。不过,若非必要,尽量不要用 long,因为它可能会降低程序运行效率。有一点要注意:如果您的编译器中,long 和 int 都是 32 位的,并且您需要使用 32 位整数,那么应该用 long,而不要用 int。只有这样,我们的程序才可以安全地移植到 16 位的计算机,因为 16 位的计算机中,int 一般也是 16 位的。类似地,如果您需要使用 64 位整数,那就用 long long。如果 int 是 32 位的话,那么使用 short 可以节省空间,不过您得确保您要处理的整数不会超出 short 的表示范围。这种“节省”对内存大的计算机来说,是没什么意义的。


5. long 型常量和 long long 型常量

    一般来说,整数常量是被当作 int 类型来存储的。如果我们使用的整数常量超出了 int 的表示范围,C 语言规定编译器自动使用 unsigned int 来处理这个常量。如果 unsigned 也不足以表示这个常量的话,编译器就会用 long。如果还表示不了的话,那就依次用 unsigned long,long long,unsigned long long。如果 unsigned long long 也表示不了,那么编译器就没辙了。注意:long long 和 unsigned long long 是 C99 特有的。例如:如果 int 是 16 位的话,它就表示不了常量 1000000。编译器会使用 long 来处理这个常量,因为 unsigned int 也表示不了 1000000 。

    同样,十六进制和八进制整数常量通常也是被作为 int 来处理。但是,当我们使用的常量超出了 int 的表示范围后,编译器会依次使用unsigned int,long,unsigned long,long long 和 unsigned long long。直到所使用的类型足以表示那个常量为止。

    有时,我们使用的是较小的常量,但是我们希望这个常量被当作 long 来处理,这就需要在这个常量后面加上后缀 l(小写字母 l)或者 L(大写字母 L)。我们应该避免使用 l ,因为 l 容易和数字 1 混淆。例如:整数常量 7 是被作为 int 来处理的,但整数常量 7L(或者 7l)是被作为 long 来处理的。类似地,在整数常量后面加上后缀 ll 或者 LL ,这个常量就会被当作 long long 来处理。例如:3LL 。如果想使用无符号整数常量的话,还要配合使用后缀 u 或者 U 。例如:2u,3U,4Lu,5ul,6LU,7LLU,8Ull,9uLL 。

    这些后缀也可以用于十六进制和八进制整数常量。例如:020L,010LL,0x30uL,0x40ull 。

参考资料:C Primer Plus, 5th Edtion By Stephen Prata
          The C Programming Language 2e By K&R
          C99 标准

ipoqing 发表于 2013-1-4 11:46:07

在GCC中,int没有默认为unsigned int,而char则默认为unsinged char,我通过实际例子进行过测试,但是请教下如何修改avr studio中的这种默认的设置呢???
页: [1]
查看完整版本: 在winAVR编译器中,char与signed char是不一样的,你知道吗?