一个很简单的char 与unsigned char 区别,请教一下大家

laiguo 2011-08-16 06:51:01

int main(int argc, char* argv)
{
char buf[4]= {0};
*(buf+2) = (char)0xDD;
printf("it is %x \n", *(buf+2));
return 0;

}
输出为it is ffffffdd
改为
unsigned char buf[4]= {0};
后输出就是对了,
it is dd
...全文
474 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
辰岡墨竹 2011-08-19
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 laiguo 的回复:]

buf+3的那个字节确实是被重写了,你不信可以自己试一下,你可以不输出你写文件试一下,就知道那个字节的内容变了,
[/Quote]

我试了一下,printf("%x", *(buf+3));
没有啊,buf+3确实没有改变啊。
我承认的确有地方误解了你的说法,但是其实问题的重点在于。你要求输出一个hex,因为你的变量是char型的,所以printf就得按signed char,在前面加了ffffff,这个符号扩展一定要有的,否则就不能表明是signed了。注意%x定义其输出结果就是Unsigned hexadecimal integer,如果直接输出a0,就是000000a0了。
举个例子,我让某个变量是-1,结果它被显示成1,那肯定是转换错误,必须有一种方式表示出负号来。比如fffffff,这样才是正确的。
注意它只是printf在显示时做的处理,并不是给你增加了3个字节。所以你只是看起来增加了宽度。
辰岡墨竹 2011-08-19
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 frankhb1989 的回复:]

引用 3 楼 i_code 的回复:

和机器相关。某些机器char就等于unsigned char。换而言之就是在某些机器上它们没有区别。

错误。C/C++的char/signed char/unsigned char是三种不同的类型。
只不过算术运算的行为char可以类似signed char也可以类似unsigned char。
[/Quote]
你才是错误的,C/C++里char只有两种signed char或unsigned char。C标准没有规定必须那个,不过由于UNIX下最早的C实现用的signed char,所以一般的编译器都默认是signed的。但是一般都提供一个编译参数设置char为unsigned。
laiguo 2011-08-17
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 bokutake 的回复:]

你怎么知道buf +3被修改了呢?你单独只用%d打印一下那个*(buf+3)看看。0xA0正好是位于GBK编码空间里的东西。所以输出时将buf+2和buf+3被作为一个汉字来解释。其实buf+3的值没有改变。
你可以先在程序最前面system("chcp 437");
就不会显示汉字了。
[/Quote]
buf+3的那个字节确实是被重写了,你不信可以自己试一下,你可以不输出你写文件试一下,就知道那个字节的内容变了,
laiguo 2011-08-17
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 bokutake 的回复:]

对,12楼说的也很对,你这个代码另一个问题是明显有访问违规。虽然你已经从堆里new一块数组空间,但是buf = "abcdefgk";这个相当于把buf的指针又指向了一个字符串常量。
之后你尝试修改常量内容,你肯定用的是TC吧,在更为严格的编译器里,必定报告内存错误,因为字符串常量是不应该被修改的。
C语言没有内置字符串类型,所以要复制字符串内容,应该用strcpy(buf, "abcdef……
[/Quote]
我只是想说明那个内存里面我放了什么,才那样赋的,而且你没有明白我的意思
辰岡墨竹 2011-08-17
  • 打赏
  • 举报
回复
对,12楼说的也很对,你这个代码另一个问题是明显有访问违规。虽然你已经从堆里new一块数组空间,但是buf = "abcdefgk";这个相当于把buf的指针又指向了一个字符串常量。
之后你尝试修改常量内容,你肯定用的是TC吧,在更为严格的编译器里,必定报告内存错误,因为字符串常量是不应该被修改的。
C语言没有内置字符串类型,所以要复制字符串内容,应该用strcpy(buf, "abcdefgk");
直接修改buf指针还会导致你之前new的空间没有指针指向,就无法delete释放其空间,产生内存泄漏。
FrankHB1989 2011-08-17
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 i_code 的回复:]

和机器相关。某些机器char就等于unsigned char。换而言之就是在某些机器上它们没有区别。
[/Quote]
错误。C/C++的char/signed char/unsigned char是三种不同的类型。
只不过算术运算的行为char可以类似signed char也可以类似unsigned char。
辰岡墨竹 2011-08-17
  • 打赏
  • 举报
回复
你怎么知道buf +3被修改了呢?你单独只用%d打印一下那个*(buf+3)看看。0xA0正好是位于GBK编码空间里的东西。所以输出时将buf+2和buf+3被作为一个汉字来解释。其实buf+3的值没有改变。
你可以先在程序最前面system("chcp 437");
就不会显示汉字了。
tangxianghenggood 2011-08-17
  • 打赏
  • 举报
回复
讨论的很激烈,要的就是这种犀利啊
jldream110 2011-08-16
  • 打赏
  • 举报
回复
顶6楼 不重复了
stein42 2011-08-16
  • 打赏
  • 举报
回复
char *buf = new char[20];
buf = "abcdefgk";
*(buf+2) = (char)0xA0;
这段代码通常会出现段错误,还有内存泄漏。


汉字是用多个字节表示的,所以输出的汉字由几个字节决定。
laiguo 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 liu111qiang88 的回复:]

引用 8 楼 laiguo 的回复:
引用 6 楼 babilife 的回复:

首先要了解一下范围
unsigned char 0~255
char -128~127


所以当你
char buf[4]= {0};时候
是0xdd=221已经超出了原始范围,所以你用单步执行的时候会看到是-35
为什么是-35呢,我们来看一下负数在内存中的表示方法补码:
即:反码+1
……
[/Quote]
看我写的7楼的红字,
火头军 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 laiguo 的回复:]
引用 6 楼 babilife 的回复:

首先要了解一下范围
unsigned char 0~255
char -128~127


所以当你
char buf[4]= {0};时候
是0xdd=221已经超出了原始范围,所以你用单步执行的时候会看到是-35
为什么是-35呢,我们来看一下负数在内存中的表示方法补码:
即:反码+1
1101 1101(221)
0010……
[/Quote]

%x 默认为整形打印的为 32为 所以 当为负数是自动扩展符号 1
laiguo 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 supermegaboy 的回复:]

引用 4 楼 laiguo 的回复:
引用 2 楼 yq_118 的回复:

char可以是有符号的,
0xDD传给它就转化为是一个负数,
调用printf时再提升为int类型,还是负数,
按16进制打印出来就是那样了。

事实是我存进去的就是一个INT型的数据,我想知道更深层次原因


char与unsigned char两者是有很大区别的,使用者很容易被两者相同的1字节……
[/Quote]
非常谢谢,讲的很好。
不过你理解错的我意思了,
我不需要保证我的存的数据是数值,我只是向里面存入数据,
例如:
char *buf = new char[20];
buf = "abcdefgk";
*(buf+2) = (char)0xA0;
读出来整个字符为“it is ab燿efgk
也就是buf+2 和buf +3的数据都被改写了,我想知道为什么.
如果正常的话,只有第三个字节是被改写为oxA0
laiguo 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 babilife 的回复:]

首先要了解一下范围
unsigned char 0~255
char -128~127


所以当你
char buf[4]= {0};时候
是0xdd=221已经超出了原始范围,所以你用单步执行的时候会看到是-35
为什么是-35呢,我们来看一下负数在内存中的表示方法补码:
即:反码+1
1101 1101(221)
0010 0010(反码)
……
[/Quote]

我是想知道前面的那三个字节是到底怎么出来的
飞天御剑流 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 laiguo 的回复:]
引用 2 楼 yq_118 的回复:

char可以是有符号的,
0xDD传给它就转化为是一个负数,
调用printf时再提升为int类型,还是负数,
按16进制打印出来就是那样了。

事实是我存进去的就是一个INT型的数据,我想知道更深层次原因
[/Quote]

char与unsigned char两者是有很大区别的,使用者很容易被两者相同的1字节二进制宽度所迷惑,以为它们是一回事,事实上两者用途完全不一样。

signed char和unsigned char是用于数值的,两者用于1字节的整数类型数值表示,而char并非用于数值表示,而是用于字符的,这就是为什么虽然有signed char和unsigned char却仍然存在char的原因。

char是实现相关的,底层类型可以是signed char和unsigned char中的一种,不过,无论哪种底层类型,都必须保证执行字符集中的字符码值必须是正的,码值的范围随1字节的位数而定,绝大多数情况的8位字节下是0到127,超出此范围的属于扩展字符集,C/C++标准不保证符号为正。

因此,如果你希望使用1字节的整数类型,不要使用char,应使用signed char或者unsigned char。

对于楼主的代码,结果随char的实现而变,如果底层类型为signed char(大多数情况),由于0xDD在signed char中为负数,因此打印的时候进行符号扩展成为ffffffdd,如果底层类型为unsigned char,则为DD。
至善者善之敌 2011-08-16
  • 打赏
  • 举报
回复
首先要了解一下范围
unsigned char 0~255
char -128~127


所以当你
char buf[4]= {0};时候
是0xdd=221已经超出了原始范围,所以你用单步执行的时候会看到是-35
为什么是-35呢,我们来看一下负数在内存中的表示方法补码:
即:反码+1
1101 1101(221)
0010 0010(反码)
+ 1
————————
0010 0011 (十六进制为-23)

然而负数显示出来的时候即又为反码加+
ff ff ff DD
laiguo 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 i_code 的回复:]

和机器相关。某些机器char就等于unsigned char。换而言之就是在某些机器上它们没有区别。
[/Quote]
这个是在PC上的
laiguo 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 yq_118 的回复:]

char可以是有符号的,
0xDD传给它就转化为是一个负数,
调用printf时再提升为int类型,还是负数,
按16进制打印出来就是那样了。
[/Quote]
事实是我存进去的就是一个INT型的数据,我想知道更深层次原因
I_code 2011-08-16
  • 打赏
  • 举报
回复
和机器相关。某些机器char就等于unsigned char。换而言之就是在某些机器上它们没有区别。
stein42 2011-08-16
  • 打赏
  • 举报
回复
char可以是有符号的,
0xDD传给它就转化为是一个负数,
调用printf时再提升为int类型,还是负数,
按16进制打印出来就是那样了。
加载更多回复(1)
再次简化代码,取消串口,直接显示结果,仍然有问题!!

疑问代码如下:
struct _USB_DATA_STRUCT
{
/*
unsigned char command_data[40];//release结果正确
int command_index;
int command_size;
int numofnod;
*/
int command_index;
int command_size;
int numofnod;
unsigned char command_data[40];//release结果错误

void SetData(unsigned char* pdata,int size)
{
if(size>40)
{
AfxMessageBox("数据太大,超范围!");
return;
}
memcpy(command_data,pdata,size);
}
};

void CTestprjDlg::OnButton1()
{
// TODO: Add your control notification handler code here
unsigned char ctem[32];//错误:32,103,104; 正确:105,110

USB_DATA_STRUCT CommandData;//需要填写要发送的数据

ctem[0]=0xee;
ctem[1]=0x01;
memset(ctem+2,0x00,30);

CommandData.SetData(ctem,32);

ShowTest(CommandData.command_data,32);
}

void CTestprjDlg::ShowTest(unsigned char* p,int nlen)
{
CString str = _T("");
for(int i=0;i <32;i++)
{
CString tmp_str;
tmp_str.Format("0x%02X ", p[i]);
str += tmp_str;
}
m_textctrl.SetWindowText(str);
}

//VC6

Debug版本没有问题,输出如:
EE 01 00 00 00...后面全0
Release版本(按Maximize speed优化)有问题,输出如:
EE 01 00 00 00 00 00 00 00 00 00 00 EE 01 00 00 00 00 00 00 00 00 00 00 EE 01 00 00 00 00 00 00

Release版本下,按以下修改没有问题。
1.调整ctem的大小。小于等于104有问题,大于等于105没有问题。
2.将ctem改为char* ctem;
ctem=new char[32];
没有问题。

3.优化方式由Maximize speed修改为Minimize code也没问题。

请教可能是什么原因?

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧