looker 发表于 2009-4-28 22:05:32

对char、unsigned char、signed char这三种类型还是比较困惑&&&&&a

先谢谢坛子里各位的解答 这阵子问了不少问题~~

RT,在C中有char、unsigned char、signed char这三种类型
http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440732.png
(原文件名:QQ截图未命名.png)
从3 item可以看出char是为了存储字符类型而设置的,但是它也是可以用来存储数字的啊
从4 item可以看出standard signed integer types一共有五种
从5 item中,plain char是什么样的类型呢?直接就是char?我只知道在IAR中是可以选择设置plain char为signed char或者为unsigned char的。关于char的这三种类型,在编译器中一般都有实现么?感觉很多都是讲char视线为signed char或者unsigned char的。plain int是否即使signed int类型?它的长度为程序运行环境的算数运算的自然长度,在32位PC中int为32位很好理解,但是在8位MCU中怎么为16位的呢?

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440731.png
(原文件名:QQ截图未命名1.png)
从15 item中有了个character types的概念,但是17 item中的integer type,是否即是char、signed char、unsigned char、signed int等,但是integer type不是即分为signed integer type和unsigned integer type的么?这里又加上了个char,从概念上来讲不是很合理的呀。

void_c 发表于 2009-4-28 23:26:24

char本身是用来存储字符的。(但如果使用者硬要存储其他数字,那是使用者自己的事。)

plain char就是char。plain是相对unsigned和signed来说的。

另外,标准C只规定char有足够存储空间存储字符,并没有规定char一定是8位。char不是8位(比如16位)也是可能的。
但不论char是多少位,sizeof(char)恒为1.

char可视为signed char或者unsigned char,但char和signed char,unsigned char并不是同一类型。
好比short,int同为16位,short可视为int,但是short和int仍然是不同的类型。

signed integer不包含char,
unsigned integer也不包含char,
char只能单独拿出来。

关于,8位机,int为何是16位?我也不明白。
听说过“标准C规定int不小于16位”的说法,但没找到确切证据。

looker 发表于 2009-4-29 11:11:52

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440854.png
(原文件名:QQ截图未命名1.png)

char本身是用来存储字符的。(但如果使用者硬要存储其他数字,那是使用者自己的事。)
plain char就是char。plain是相对unsigned和signed来说的。
————————————————————————————————————————————————
这个已经明白。但是很多编译器只实现了这三种类型中的两种,而字符的ASCII也可以视为数字的,存储的表示形式是确定的。而signed char是为了将char实现为unsigned char而加入的。当只实现了两种时,不就有两种类型相同了么?

void_c 发表于 2009-4-29 11:41:27

一个简单测试例子:

char *p_char;
unsigned char *p_unsigned_char;
signed char *p_signed_char;

int *p_int;
unsigned int *p_unsigned_int;
signed int *p_signed_int;

short *p_short;

p_char=(void *)0;
p_unsigned_char=p_char;
//不管char是否有符号,char *与unsigned char *不是兼容类型

p_signed_char=p_char;   
//不管char是否有符号,char *与signed char *不是兼容类型


p_int=(void *)0;
p_unsigned_int=p_int;
//int *与unsigned int *不是兼容类型

p_signed_int=p_int;
//int *与signed int *是兼容类型

p_short=p_int;
//不管short位数是否与int相同,short *与int *不是兼容类型。

snoopyzz 发表于 2009-4-29 11:51:18

一般约定
char是8位(并非绝对),short是16位(好像有规定),long是32位(好像有规定),
至于int取决于平台字长,8/16位处理器int是16位,32位处理器int是32位

void_c 发表于 2009-4-29 12:10:40

short是16位(好像有规定),long是32位(好像有规定),
——————————————————————————

规定出自哪里?规定原文是是什么?
没有这些,等于白说。

looker 发表于 2009-4-29 12:37:05

上官先生,您在3F给出的测试例程,我在AVRGCC上测试了下,warning如下:
http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440889.png
(原文件名:QQ截图未命名2.png)

只有short与int是不兼容类型,而unsigned与signed这两种类型之间只是提示符号位之间存在差别
刚google了下,发现这个错误“../test.c:24: warning: pointer targets in assignment differ in signedness”
在linux编程中是大量存在的,有些比较大型的程序在用户自己编译时也会出现很多这个warnings,按道理开源社区给出程序不应该存在这个warning的呀

而p_signed_int=p_int;
//int *与signed int *是兼容类型
更确切地说应该是same type吧

looker 发表于 2009-4-29 13:56:04

A ‘plain’ int object has the natural size suggested by the architecture of the execution environment.
感觉这一句很重要,特别是natural size这个概念的理解
这里我觉得“natural size suggested by the architecture of the execution environment”应该是指操作系统或者说硬件的环境,而非编译器的实现。
在32位PC/操作系统中,sizeof(int)即为4;
在64位PC/操作系统中,sizeof(int)即为8;(没有用过64位系统,所以只是推测)

而在8位机中,sizeof(int)应该为1的呀

已经证实8位MCU中,C的int是2个字节的,而在运算时都会有整型提升,这样效率上不就打折扣了么?因为8位MCU中寄存器是8位的,而ALU也大多是8位的

looker 发表于 2009-4-29 14:24:09

short是16位(好像有规定),long是32位(好像有规定)
——————————————————————————————————————————————
这个我找到依据了,如下图所示:

所以:
对于short类型,最小是2个字节
对于int类型,最小是2个字节
对于long类型,最小是4个字节
对于long long类型,最小是8个字节

而一般short的类型长度不能超过int,int的类型长度不能超过long,long long的类型长度不能超过long long
这个在标准中还没有找到


http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440910.png
(原文件名:QQ截图未命名3.png)

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440909.png
(原文件名:QQ截图未命名4.png)

Etual 发表于 2009-4-29 17:03:07

(好吧,以下发现仅代表我自己的意见....没有证据.....)

char 有一个默认值,到底这个默认值是 signed char 还是 unsigned char
这个要编译器的实现,另外,GCC有个选项可以改变,例如 avr-gcc 的
-funsigned-char
强制指定,那么编译器将全部的char作为 unsigned char处理,
否非你完整的写 signed char

一般来说 int 代表的是机器字长,16位机为 16位,32位机为32位,但是说白了
无论你怎么研究C语言的标准,当你拿到一个新的编译器的时候,这种规则都要
见鬼去,不同C语言的编译器可以根据实际情况做调整的,例如我用过台湾的一个
MUC的C编译器,int就是8位的 ...... 所以我觉得,记住一般情况就足够了
具体应该以什么标准,请翻阅你的编译器手册。如果那个手册没有写,我想
这个版本的C编译器也可以扔掉了。

short 是 short int 的缩写
long 是 long int 的缩写

另外,对于GCC,在AVR的机器相关选项中有这么一项
详见GCC online manual中的3.17 Hardware Models and Configurations
其中的AVR option。

-mint8
Assume int to be 8 bit integer. This affects the sizes of all types: A char will be 1 byte, an int will be 1 byte, an long will be 2 bytes and long long will be 4 bytes. Please note that this option does not comply to the C standards, but it will provide you with smaller code size.

问题的处理是灵活di。

最后,对楼上的几位兄弟的仔细研究我倒是很佩服,m(_ _)m//bow

snoopyzz 发表于 2009-4-29 17:35:07

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440957.gif
(原文件名:QQ截图未命名.gif)

char默认是singned还是unsigned取决于实现,并非未定义,所以编译器文档中一定能找得到相关说明

snoopyzz 发表于 2009-4-29 17:47:38

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_440958.GIF
(原文件名:QQ截图未命名2.GIF)

整型字长从limits.h中获取...

话说我第一次知道还有long double这种类型,惭愧呀-_-
======================
忘说了,以上两图均截自C89标准
中华人民共和国国家标准 GB/T 15272-94
程序设计语言C

looker 发表于 2009-4-29 21:40:25

char 有一个默认值,到底这个默认值是 signed char 还是 unsigned char
这个要编译器的实现,另外,GCC有个选项可以改变,例如 avr-gcc 的
-funsigned-char
强制指定,那么编译器将全部的char作为 unsigned char处理,
否非你完整的写 signed char
————————————————————————————————————————————————————————————
GCC用的很少,但是在IAR中我是很老实的写signed char和unsigned char的,在IAR中是可以设置char是unsigned char还是signed char的

looker 发表于 2009-4-29 21:52:00

一般来说 int 代表的是机器字长,16位机为 16位,32位机为32位,但是说白了
无论你怎么研究C语言的标准,当你拿到一个新的编译器的时候,这种规则都要
见鬼去,不同C语言的编译器可以根据实际情况做调整的,例如我用过台湾的一个
MUC的C编译器,int就是8位的 ...... 所以我觉得,记住一般情况就足够了
具体应该以什么标准,请翻阅你的编译器手册。如果那个手册没有写,我想
这个版本的C编译器也可以扔掉了。

short 是 short int 的缩写
long 是 long int 的缩写

另外,对于GCC,在AVR的机器相关选项中有这么一项
详见GCC online manual中的3.17 Hardware Models and Configurations
其中的AVR option。

-mint8
Assume int to be 8 bit integer. This affects the sizes of all types: A char will be 1 byte, an int will be 1 byte, an long will be 2 bytes and long long will be 4 bytes. Please note that this option does not comply to the C standards, but it will provide you with smaller code size.

问题的处理是灵活di。
—————————————————————————————————————————————————————————
8位的int倒是第一回听说 长见识了 呵呵~~

looker 发表于 2009-4-29 21:53:08

char默认是singned还是unsigned取决于实现,并非未定义,所以编译器文档中一定能找得到相关说明
——————————————————————————————————————————————
char既不是signed也不是unsigned的

snoopyzz 发表于 2009-4-29 22:18:27

char在实现上不是signed char就是unsigned char...
类型上算是不同类型,但实现上必定在两者中取其一

snoopyzz 发表于 2009-4-29 22:22:15

所谓“实现”和“未定义”是标准中提到的专用说法
“实现”取决于编译器,是标准中允许的正确做法
“未定义”也取决于编译器,但是标准中不承认的非法操作

也就是说编译器把char实现成signed char或unsigned char都是正确的,
因为可以保证放下标准中的全部字符集,并且值为正,就是正确的...

richardbao 发表于 2009-4-30 01:31:29

13楼的定义最准确,为什么老是要咬着和电脑或单片机的位数不放呢,16位机,32位机说的是硬件同一时间处理数据位数的能力,而C和其他各种编程语言对于各种数据类型位数的定义取决于complier对各种数据类型的定义,基本上和硬件的位数没有什么直接关系。
如果要知道确切的对各种类型的定义,请参考complier对这些类型的声明,或者参考相应语言所设定的标准。
其实楼主上面的那些英文说明很像是对一个单片机做complier的设计要求。
“plain”char类型是真正的字符类型是用来声明字符用的
unsinged,singed cha类型是用来声明数值的,他不是用来声明字符用的。为什么有这两个定义呢,其实标准的C里面是没有这两个类型的定义的,大概是因为单片机的存储空间没有电脑多,而用这两个声明来节省单片机的存储空间。举例:int类型是16位的,如果你的程序只需要一个0-255之间的数值,那么用int的话,高8位就被白白浪费了,而且如果你的单片机是8为的话,那么需要两个周期读入所需的数值。那如果用char的话,那么正好是8位,正好符合程序的要求。但是如果你要求的值是从-128-127之间的话,那也是8位,所以就产生了signed char,为了是程序不产生歧义所以就又有了unsigned char. 所以为了让你的程序清晰可读,不要把char和unsigned char混用,虽然他们是相同的,但是一个定义了字符类型,一个定义了数值类型。
为什么8位单片机的int是16位的呢,这是C语言的标准所定的。32位的单片机是32位的也是C语言标准所定的,没有什么为什么的。如果8位单片机的int也定义为8位,那么int就和char类型所定义的类型重复了。
请你跳出单片机再思考上面的问题,他会比较好理解。

snoopyzz 发表于 2009-4-30 09:08:41

LS,谁教你char 和unsigned char相同了。。。
你再向上看看,没人说两者相同
C语言标准也没有强制8位单片机的int就是16位的,
C语言标准与平台是无关的...不要把你所认识到的普遍“常识”就强解释为“标准”,
或者你把你所谓的“标准”找出来。
最后,字长和符号重复的类型难道还少吗?

LS是典型的由果塑因,存在即有理,难道我和LS的各位都不知道一些“常识”吗?
这里探讨的是“标准”

dr2001 发表于 2009-4-30 09:25:33

支持楼上的看法。

既然是讨论标准,那就需要有白纸黑字的东西。如果有什么观点,至少,要告诉大家是哪个版本的文档的哪个章节,哪句话。
标准是在实现之上的,也许很多是常识,众多编译系统都是这么实现的;
但是,这并不意味着标准,就是这么规定的。只要符合标准确认的部分,就是符合标准的。

richardbao 发表于 2009-4-30 11:47:54

Please read C language standard. It mentioned that int type at lease 16 bits on page 124. It didn't say anything about unsigned and signed char on the standard. As I know unsinged and signed char is a part of Embeding system not for standard for C language.
The standard link is : http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf

richardbao 发表于 2009-4-30 11:49:02

say = see by typing error.

looker 发表于 2009-4-30 13:05:24

另外,对于GCC,在AVR的机器相关选项中有这么一项
详见GCC online manual中的3.17 Hardware Models and Configurations
其中的AVR option。

-mint8
Assume int to be 8 bit integer. This affects the sizes of all types: A char will be 1 byte, an int will be 1 byte, an long will be 2 bytes and long long will be 4 bytes. Please note that this option does not comply to the C standards, but it will provide you with smaller code size.
这个摘自http://gcc.gnu.org/onlinedocs/网址的GCC 4.4.0 Manual

问题的处理是灵活di。
————————————————————————————————————————————————
这个很好的,在实际程序中可以尝试下~~
这样不仅能减小代码的大小,应该还能提高程序运行的速度,特别是涉及很多算术运算时

void_c 发表于 2009-4-30 13:10:43

我程序里,除了非常特殊的位置用int外,其他地方一概不直接用shot,int long.

用int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t代替(确切说,我习惯uint8代替uint8_t)。
这些已经包含在C语言标准规定的头 文件stdint.h 里面。

Gorgon_Meducer 发表于 2009-4-30 13:11:51

尽可能避免使用默认类型,请使用stdint.h中定义的类型……否则无任何可移植性而言

snoopyzz 发表于 2009-4-30 13:13:00

实际时我都是typedef出u8,u16,u32,s8,s16,s32
按需选取合适类型...
这个选项小心使用...8位的int很可能有你不想看到的情况
比如循环变量变成8位的int,下面这个就会有问题
int i;
for(i=0;i<200;i++)
{
}
你会发现128次就跳出循环了

looker 发表于 2009-4-30 13:30:41

有两个英文词汇得首先单独提出来:
implementation这个一般指的是标准中各种类型等在编译器中的具体实现
representation这个是指每种类型的数据在存储介质中的每位的保存数据(bit mode),即所谓的表示形式。譬如signed char的数据,在转换成unsigned char时,其在存储介质中保存的每位的数据不做任何改变,即表示形式不变,只是对应的数据发生了变化而已。

looker 发表于 2009-4-30 13:32:29

多谢楼上各位的回帖~~
每拿到一个编译器,一般都需要关注哪些头文件呢?
我现在都是通过typedef来自己定义类型的,有点费力~~

有点不明白21F所说的:say = see by typing error

looker 发表于 2009-4-30 13:35:37

13楼的定义最准确,为什么老是要咬着和电脑或单片机的位数不放呢,16位机,32位机说的是硬件同一时间处理数据位数的能力,而C和其他各种编程语言对于各种数据类型位数的定义取决于complier对各种数据类型的定义,基本上和硬件的位数没有什么直接关系。
如果要知道确切的对各种类型的定义,请参考complier对这些类型的声明,或者参考相应语言所设定的标准。
其实楼主上面的那些英文说明很像是对一个单片机做complier的设计要求。
“plain”char类型是真正的字符类型是用来声明字符用的
unsinged,singed cha类型是用来声明数值的,他不是用来声明字符用的。为什么有这两个定义呢,其实标准的C里面是没有这两个类型的定义的,大概是因为单片机的存储空间没有电脑多,而用这两个声明来节省单片机的存储空间。举例:int类型是16位的,如果你的程序只需要一个0-255之间的数值,那么用int的话,高8位就被白白浪费了,而且如果你的单片机是8为的话,那么需要两个周期读入所需的数值。那如果用char的话,那么正好是8位,正好符合程序的要求。但是如果你要求的值是从-128-127之间的话,那也是8位,所以就产生了signed char,为了是程序不产生歧义所以就又有了unsigned char. 所以为了让你的程序清晰可读,不要把char和unsigned char混用,虽然他们是相同的,但是一个定义了字符类型,一个定义了数值类型。
为什么8位单片机的int是16位的呢,这是C语言的标准所定的。32位的单片机是32位的也是C语言标准所定的,没有什么为什么的。如果8位单片机的int也定义为8位,那么int就和char类型所定义的类型重复了。
——————————————————————————————————————————————————————————
首先,在standard C中已经有了signed char和unsigned char这两个类型定义了
而char是用来声明字符的,而signed char和unsigned char是用来声明数值的,这个应该很清楚了,至于char在各个编译器中是怎样实现的,这个就不是很清楚,一般的好像都是用signed char或unsigned char来实现char的,这三种类型的对象在存储介质中的表现形式是一样的,所以只要能注意好,三种类型之间的转换是没有问题的

补上20F提到的参考(其实我在8F给出的截图已经能说明问题了,关于int类型的长度):
http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_441107.png
(原文件名:QQ截图未命名5.png)

looker 发表于 2009-4-30 13:49:02

实际时我都是typedef出u8,u16,u32,s8,s16,s32
按需选取合适类型...
这个选项小心使用...8位的int很可能有你不想看到的情况
比如循环变量变成8位的int,下面这个就会有问题
int i;
for(i=0;i<200;i++)
{
}
你会发现128次就跳出循环了
————————————————————————————————————————————————
如果在有意识的那样做 则就不会碰上这个问题了
因为C标准中规定是有整型提升的,这样应该能稍微提升下效率的~~虽然这样的程序没有什么可移植性

looker 发表于 2009-4-30 17:11:11

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_441133.png
(原文件名:ourdev_440889.png)

这个地方还不是很明白,为什么unsigned类型与signed类型之间相互赋值提示的是“符号不一致”呢?他们是不兼容类型的呀

cjr82123 发表于 2009-4-30 17:19:04

Mark起来慢慢看!

void_c 发表于 2009-4-30 17:56:57

“符号不一致”是不兼容的一种具体表现形式。

richardbao 发表于 2009-4-30 21:18:50

首先谢谢looker指出我对unisigned和signed char的看法,他确实是标准C语言的一部分,见上面我所贴出的C标准的43-44页。

这个地方还不是很明白,为什么unsigned类型与signed类型之间相互赋值提示的是“符号不一致”呢?他们是不兼容类型的呀

答:就像我上面说的,两种类型定义都是定义了一个8bits的整形数,但是一个是从0~255,而另外一个是从-128~127也就是说从0x00~0xFF中有一部分数的表达在这两种类型定义中是不同的,见下表。所以上面系统会给出一个警告。
具体说吧,如果你的程序中数值的应用范围在0-127之间,那么这个警告其实对你的程序不会有什么不良影响,但是如果你定义了char类型,如而且使用范围在0-255之间,那么强制转换是会把128-255之间的数转换成负数,反之亦然。

看了你贴出的警告,好像不是关于char类型的,而是关于指针的,好像是你把错误的指针类型赋值给其他类型的指针。

实际时我都是typedef出u8,u16,u32,s8,s16,s32
按需选取合适类型...
这个选项小心使用...8位的int很可能有你不想看到的情况
比如循环变量变成8位的int,下面这个就会有问题
int i;
for(i=0;i<200;i++)
{
}
你会发现128次就跳出循环了
因为普通的整数是被定义为signed的整形,所以到范围是-128~127,所以当你从0-127之后i就变成了负数,i就小于200了程序就跳出了。

还有对你提到的需要了解哪些头文件,我认为是需要用什么查什么,因为大多数complier的设计公司都会遵守标准设计的。你只要有一本对应语言的参考书,上面对各种类型定义的解释,估计不会和你使用的有大的出入。

see=say是我对我18贴的补充说明,因为打字打错了

Unsigned 8-bit integers (No sign-bit)

Binary Hex Decimal
0000 0000 0x00 0
0000 0001 0x01 1
0000 0010 0x02 2
. . . . . . . . .
1111 1101 0xFD 253
1111 1110 0xFE 254
1111 1111 0xFF 255


Signed 8-bit integers (Sign + Magnitude)
S Magnitude
1 000 0000 0x80 -128
1 000 0001 0x81 -127
1 000 0010 0x82 -126
. . .
1 111 1101 0xFD -3
1 111 1110 0xFE -2
1 111 1111 0xFF -1
0 000 0000 0x00 0
0 000 0001 0x01 1
0 000 0010 0x02 2
. . .
0 111 1101 0x7D 125
0 111 1110 0x7E 126
0 111 1111 0x7F 127

looker 发表于 2009-4-30 21:47:44

多谢楼上~~

看了你贴出的警告,好像不是关于char类型的,而是关于指针的,好像是你把错误的指针类型赋值给其他类型的指针。
——————————————————————————————————————————————————
确实是unsigned char *、signed char *、char *这三种指针,这三种类型的比较跟unsigned char、signed char、char的比较是一致的,所以。。。


还有对你提到的需要了解哪些头文件,我认为是需要用什么查什么,因为大多数complier的设计公司都会遵守标准设计的。你只要有一本对应语言的参考书,上面对各种类型定义的解释,估计不会和你使用的有大的出入。
——————————————————————————————————————————————————
这里提到的需要查看的头文件,主要是开始考虑到可移植性问题
有大侠提到不要在自己的程序中直接使用标准类型 建议参考stdint.h头文件中的声明,所以才有此一问~~


正如我在26F提到的:
有两个英文词汇得首先单独提出来:
implementation这个一般指的是标准中各种类型等在编译器中的具体实现
representation这个是指每种类型的数据在存储介质中的每位的保存数据(bit mode),即所谓的表示形式。譬如signed char的数据,在转换成unsigned char时,其在存储介质中保存的每位的数据不做任何改变,即表示形式不变,只是对应的数据发生了变化而已。
对于signed和unsigned类型,他们在存储介质的中表示形式是一样的,只是因为是不同的类型,所以对其的解释不一样

chenhuanbang 发表于 2010-8-24 16:58:51

mark

maomeijian 发表于 2012-11-15 10:26:22

怎么感觉是众说纷纭呢。
页: [1]
查看完整版本: 对char、unsigned char、signed char这三种类型还是比较困惑&&&&&a