原文:https://blog.csdn.net/guotianqing/article/details/77341657

背景
最近在项目中遇到了一个编译警告,是因为定义的变量为char[],而在使用时作为函数的unsigned char*类型的参数调用。这个警告很容易避免,但是char*和unsigned char*到底有什么区别呢,本文作一个简单的探讨。

char 和 unsigned char 的区别
在C中,默认的基础数据类型均为signed,如定义变量为int,long等,都为有符号的。如果要定义无符号类型,必须显式地在变量类型前加unsigned。

char vs unsigned char
相同点:在内存中都是一个字节,8位(2^8=256),都能表示256个数字
不同点:char的最高位为符号位,因此char能表示的数据范围是-128~127,unsigned char没有符号位,因此能表示的数据范围是0~255

实际使用中,如普通的赋值,读写文件和网络字节流都没有区别,不管最高位是什么,最终的读取结果都一样,在屏幕上面的显示可能不一样。

但是要把一个char类型的变量赋值给int、long等数据类型或进行类似的强制类型转换时时,系统会进行类型扩展,这时区别就大了。对于char类型的变量,系统会认为最高位为符号位,然后对最高位进行扩展,即符号扩展。若最高位为1,则扩展到int时高位都以1填充。对于unsigned char类型的变量,系统会直接进行无符号扩展,即0扩展。扩展的高位都以0填充。所以在进行类似的操作时,如果char和unsigned char最高位都是0,则结果是一样的,若char最高位为1,则结果会大相径庭。

可以使用的下面的小程序验证一下:

#include <stdio.h>

static void func(unsigned char uc)
{
char c;
int i, j;
unsigned int ui, uj; c = uc;
i = (int)c;
j = (int)uc;
ui = (unsigned int)c;
uj =(unsigned int)uc;
printf("%%c: %c, %c\n", c, uc);
printf("%%x: %x, %x\n", c, uc);
printf("%%u: %u, %u\n", ui, uj);
printf("%%d: %d, %d\n", i, j);
} int main(int argc, char *argv[])
{
func(0x80);
func(0x7f); return 0;
}

  

运行结果如下:

%c: �, �
%x: ffffff80, 80
%u: 4294967168, 128
%d: -128, 128
---------------------------
%c:,
%x: 7f, 7f
%u: 127, 127
%d: 127, 127

对于char来说,0x80用二进制表示为1000 0000,当它作为char赋值给unsigned int或 int 时,系统认为最高位是符号位,会对最高位进行扩展。而0x7F用二进制表示为0111 1111,最高位为0,不会扩展。对于unsigned char来说,不管最高位是0,还是1,都不会做扩展。

char* 和 unsigned char*的区别
char* 和 unsigned char* 也具有类似的区别,如下面测试程序所示:

char*是有符号的,如果大于127即0x7F的数就是负数了,使用%x格式化输出,系统自动进行了符号扩展,就会产生变化。

所以在涉及到类型提升的上下文中,要注意使用char*和unsinged char*的区别。

#include <stdio.h>

int main(int argc, char *argv[])
{
unsigned char k = 0;
int i = -1;
short a = -12345;
char *p;
unsigned char *q; printf("sizeof(i) = %d\n",sizeof(i));
printf("sizeof(a) = %d\n",sizeof(a));
printf("-----------------------------\n");
printf("begin p(char):\n");
p = (char*)&a;
printf("a = %u | %d\n",a,a);
for(k=0;k<sizeof(a);k++)
{
printf("0x%x ",*(p++));
}
printf("\n");
p = (char*)&i;
printf("i = %u | %d\n",i,i);
for(k=0;k<sizeof(i);k++)
{
printf("0x%x ",*(p++));
}
printf("\n");
printf("-1 > 0u: %s\n",(-1>0u ? "true":"false")); printf("-----------------------------\n");
printf("begin q(unsigned char):\n");
q = (unsigned char*)&a;
printf("a = %u | %d\n",a,a);
for(k=0;k<sizeof(a);k++)
{
printf("0x%x ",*(q++));
}
printf("\n");
q = (unsigned char*)&i;
printf("i = %u | %d\n",i,i);
for(k=0;k<sizeof(i);k++)
{
printf("0x%x ",*(q++));
}
printf("\n");
printf("-1 > 0u: %s\n",(-1>0u ? "true":"false")); return 0;
}

  

c语言中 char* 和 unsigned char* 的区别浅析(转)的更多相关文章

  1. char、signed char、unsigned char的区别总结。

    转载地址:http://hi.baidu.com/thewillreigns/blog/item/67e665c4296e69c038db492d.html char 和 unsigned char是 ...

  2. char, signed char, and unsigned char in C++

    关于这三者的区别stackoverrflow里有一个答案是这样说的: 3.9.1 Fundamental types [basic.fundamental] 1 Objects declared as ...

  3. signed char、unsigned char

    什么是无符号char类型?与常见的char类型有何不同? 在c++中有三种不同的字符类型:char,signed char,unsigned char.如果要应用与文本字符,就使用不加限制的char类 ...

  4. char 与 unsigned char的本质区别

    在C中,默认的基础数据类型均为signed,现在我们以char为例,说明(signed) char与unsigned char之间的区别 首先在内存中,char与unsigned char没有什么不同 ...

  5. char、signed char 和 unsigned char 的区别

    ANSI C 提供了3种字符类型,分别是char.signed char.unsigned char.而不是像short.int一样只有两种(int默认就是signed int). 三者都占1个字节( ...

  6. char与unsigned char 差别

    char 与 unsigned char的本质差别 http://bbs.csdn.net/topics/270080484 同一个内存内容:10010000      你用char*   解释是-1 ...

  7. char 与 unsigned char的区别和取值范围

    1.char和unsigned char 都是一个byte,8个bit.char是无符号类型,首位bit是符号位. 2.取值范围不同: (1)unsigned char的取值范围:0~2^8-1(0~ ...

  8. char 与 signed char 和 unsigned char三者之间的关系

    # char 与 signed char 和 unsigned char三者之间的关系 三者都占用 1个字节,即 8 bit signed char取值范围(-128, 127) unsigned c ...

  9. 关于 char 和 unsigned char 的区别

    首先卖个关子: 为什么网络编程中的字符定义一般都为无符号的字符?   char buf[16] = {0}; unsigned char ubuf[16] = { 0 };   上面两个定义的区别是: ...

随机推荐

  1. gcc, ld

    GCC gcc除了具备基本的c文件编译功能外,还把其它工具的功能也集成了进来,比如as的汇编功能,ld的链接功能. 因此,gcc也可以通过-Wa, option,将option传给汇编器as:也可以通 ...

  2. springmvc maven idea 多模块开发(三):建立子模块

    传统的多模块方式是建立domain.dao.service等,这种方式是按照软件架构进行分割,现在更多的应该是倾向按照功能来解耦,module前期可以配置成jar,后期也可以建立独有的页面,独立的站点 ...

  3. pikachu-远程代码、命令执行漏洞(RCE)

    一.RCE概述 1.1 什么是RCE? RCE漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统. 1.2 远程系统命令执行 一般出现这种漏洞,是因为应用系统从设计上需要 ...

  4. openlayers6实现webgl点图层渲染效果(附源码下载)

    前言:openlayers6推出来的有一段时间,推出来的新特性见:https://github.com/openlayers/openlayers/releases/该版本的主要功能是能够组合具有不同 ...

  5. CentOS、Ubuntu的安装

    Linux使用最广泛的2个发行版:CentOS.Ubuntu. CentOS安全性高,常用作企业的服务器,Ubuntu常用作个人桌面. 常见的虚拟机有2个: VM VirtualBox,这个是Orac ...

  6. 7.python虚拟环境详解

    1.为什么创建虚拟环境? 和其他大多数现代编程语言一样,Python对包和模块的下载.存储以及管理有其自己的一套方法,Python的包一般都存在几个特定的地方,大部分系统包会存在sys.prefix指 ...

  7. python filter函数(40)

    一.filter函数简介 filter函数主要用来筛选数据,过滤掉不符合条件的元素,并返回一个迭代器对象,如果要转换为列表list或者元祖tuple,可以使用内置函数list() 或者内置函数tupl ...

  8. SpringCloud踩坑

    今天在使用 SpringCloud 时遇到了一个问题,感觉有不少小伙伴会遇到,所以记录下来 版本说明 SpringBoot 2.2.4.RELEASE SpringCloud Greenwich.SR ...

  9. fatal: HttpRequestException encountered

    报错:fatal: HttpRequestException encountered 解决方法 Github 禁用了TLS v1.0 and v1.1,必须更新Windows的git凭证管理器,才行. ...

  10. 教你如何理解JAVA的I/O类库

    花括号MC(huakuohao-mc):关注JAVA基础编程及大数据,注重经验分享及个人成长. Java 的 I/O 流,说简单也简单,说复杂也复杂.复杂是因为进行一次常规的文件 I/O 操作通常要用 ...