c语言无符号二进制为什么是两个字节,C / C ++为什么对二进制数据使用无符号字符?...

C / C ++为什么对二进制数据使用无符号字符?

是否真的有必要像在某些字符编码或二进制缓冲区中使用的库中那样,使用char来保存二进制数据? 为了弄清楚我的问题,请看下面的代码-

char c[5], d[5];

c[0] = 0xF0;

c[1] = 0xA4;

c[2] = 0xAD;

c[3] = 0xA2;

c[4] = '\0';

printf("%s\n", c);

memcpy(d, c, 5);

printf("%s\n", d);

这两个char都正确输出了signed char,其中unsigned char是十六进制的Unicode代码点char的编码。

甚至char也正确复制了char保留的位。

有什么理由可以主张使用char而不是signed char?

在其他相关问题中,突出显示char,因为它是唯一(字节/最小)数据类型,可以通过C规范保证没有填充。 但是,如以上示例所示,输出似乎不受任何填充的影响。

我已经使用VC ++ Express 2010和MinGW来编译以上内容。 虽然VC给出了警告

char

输出似乎没有反映出这一点。

附言 这可能被标记为可能的重复项。字节缓冲区应该是带符号的还是无符号的char缓冲区? 但我的意图是不同的。 我在问为什么应该在char上正常工作呢?

更新:要引用N3337,

char

2对于琐碎的任何对象(基类子对象除外)   可复制的类型T,对象是否持有类型的有效值   T,组成对象的基础字节(1.7)可以复制到   char或unsigned char的数组。 如果内容为char数组   或将未签名的字符复制回对象,则对象应   随后保留其原始值。

鉴于上述事实,并且我的原始示例是在Intel计算机上,其char默认为signed char,因此仍然不确定是否应将unsigned char优先于char。

还要别的吗?

8个解决方案

84 votes

在C中,signed char数据类型是唯一同时具有以下所有三个属性的数据类型

它没有填充位,即所有存储位都对数据值有贡献的位置

从该类型的值开始的按位运算,当转换回该类型时,不会产生溢出,陷阱表示或未定义的行为

它可以在不违反“别名规则”的情况下别名其他数据类型,也就是说,将保证通过不同类型的指针访问同一数据

如果这些是您要查找的“二进制”数据类型的属性,则应绝对使用signed char。

对于第二个属性,我们需要一种类型为signed char的类型。对于所有这些转换,均使用模数算法定义,在大多数99%的体系结构中,此处取模char、256。 所有较宽值到unsigned char的所有转换仅对应于截断最低有效字节。

其他两个字符类型通常不能相同。 signed char无论如何都已签名,因此无法正确定义不适合它的值的转换。 char并非固定为已签名或未签名,但在将您的代码移植到的特定平台上,即使未在您的代码上未签名,也可能已签名。

Jens Gustedt answered 2020-02-04T17:33:09Z

13 votes

比较单个字节的内容时,您会遇到大多数问题:

char c[5];

c[0] = 0xff;

/*blah blah*/

if (c[0] == 0xff)

{

printf("good\n");

}

else

{

printf("bad\n");

}

可以打印“ bad”,因为根据您的编译器,c [0]将被符号扩展为-1,这与0xff完全不同

Tom Tanner answered 2020-02-04T17:33:34Z

12 votes

普通的char类型是有问题的,除了字符串之外,不应用于任何其他类型。 char的主要问题在于,您不知道它是签名的还是未签名的:这是实现定义的行为。 这使得char与int等有所不同,始终保证int是已签名的。

尽管VC发出警告...常量值被截断

它告诉您您正在尝试将int文字存储在char变量中。 这可能与签名有关:如果尝试在签名字符中存储值> 0x7F的整数,则可能会发生意外情况。 形式上,这是C语言中未定义的行为,尽管实际上,如果尝试将结果打印为存储在(有符号)char中的整数值,则只会得到一个奇怪的输出。

在这种情况下,警告无关紧要。

编辑:

在其他相关问题中,突出显示了无符号字符,因为它是唯一(字节/最小)数据类型,可以通过C规范保证没有填充。

理论上,按照C11 6.2.6.2,除无符号字符和有符号字符外,所有整数类型都允许包含“填充位”:

“对于除无符号字符以外的无符号整数类型,   对象表示应分为两组:值位和   填充位(后者不需要任何)。”

“对于有符号整数类型,对象表示的位应   分为三组:值位,填充位和符号   一点。 不需要任何填充位; 签名的字符不应具有   任何填充位。”

C标准故意模糊不清,允许使用这些理论填充位,因为:

它允许使用与标准8位符号表不同的符号表。

它允许实现定义的有符号性和奇怪的有符号整数格式,例如一个人的补码或“符号和大小”。

整数不一定会使用分配的所有位。

但是,在C标准之外的现实世界中,以下条件适用:

符号表几乎可以肯定是8位(UTF8或ASCII)。 存在一些奇怪的异常,但是干净的实现在实现大于8位的符号表时使用标准类型wchar_t。

签名始终是二进制的补充。

整数始终使用分配的所有位。

因此,没有真正的理由使用无符号字符或有符号字符只是为了躲避C标准中的某些理论情况。

Lundin answered 2020-02-04T17:35:11Z

6 votes

字节通常是无符号的8位宽整数。

现在,char不指定整数的符号:在某些编译器上,char可以是带符号的,而在另一些编译器上,它可以是无符号的。

如果我在您编写的代码中添加了一位移位操作,那么我将有未定义的行为。 添加的比较也会产生意外结果。

char c[5], d[5];

c[0] = 0xF0;

c[1] = 0xA4;

c[2] = 0xAD;

c[3] = 0xA2;

c[4] = '\0';

c[0] >>= 1; // If char is signed, will the 7th bit go to 0 or stay the same?

bool isBiggerThan0 = c[0] > 0; // FALSE if char is signed!

printf("%s\n", c);

memcpy(d, c, 5);

printf("%s\n", d);

关于编译期间的警告:如果对char进行签名,则您尝试分配值0xf0,该值不能在签名的char中表示(范围-128到+127),因此它将被强制转换为签名的值(- 16)。

将char声明为unsigned将删除警告,并且始终保持良好的构建而没有任何警告总是很好。

Paolo Brandoli answered 2020-02-04T17:35:49Z

4 votes

普通unsigned char类型的签名是由实现定义的,因此,除非您实际处理字符数据(使用平台的字符集的字符串-通常为ASCII),通常最好通过使用signed char明确指定签名 或unsigned char。

对于二进制数据,最佳选择最有可能是unsigned char,尤其是如果将对数据执行按位运算(特别是移位,这种行为与有符号类型的行为与无符号类型的行为不同)。

Sander De Dycker answered 2020-02-04T17:36:14Z

2 votes

我问为什么应该用unsigned char键入似乎可以正常工作的字符?

如果您做的事情不是标准意义上的“正确”,那么您将依赖未定义的行为。 您的编译器可能会按照您今天想要的方式执行此操作,但是您不知道明天会执行什么操作。 您不知道GCC或VC ++ 2012的功能。或者即使行为取决于外部因素或Debug / Release编译等。一旦离开标准的安全路径,也可能会遇到麻烦。

Philipp answered 2020-02-04T17:36:39Z

2 votes

那么,您怎么称呼“二进制数据”? 这是一堆比特,没有任何意义的软件将其称为“二进制数据”。 最接近的原始数据类型是什么,它向这些位中的任何一位传达了缺乏任何特定含义的想法? 我认为unsigned char。

chill answered 2020-02-04T17:36:59Z

2 votes

像某些在字符编码或二进制缓冲区上工作的库中一样,真的需要使用无符号字符来保存二进制数据吗?

“真的”有必要吗? 没有。

但是,这是一个非常好的主意,并且有很多原因。

您的示例使用printf,它不是类型安全的。 也就是说,printf从格式字符串而不是数据类型中获取格式提示。 您可以轻松地尝试:

printf("%s\n", (void*)c);

...结果将是相同的。 如果使用c ++ iostream尝试相同的操作,结果将有所不同(取决于c的带符号性)。

有什么推理可能会提倡使用无符号字符而不是纯字符?

Unsigned指定数据的最高有效位(对于unsigned char,第8位)表示符号。 由于您显然不需要这样做,因此应指定数据是无符号的(“符号”位表示数据,而不是其他位的符号)。

utnapistim answered 2020-02-04T17:37:46Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
200个经典C程序源码(包括基础篇+数据结构篇+数值计算与趣味数学篇+图形篇+系统篇+常见试题解答篇) 第一部分 基础篇 001 第一个C程序 002 运行多个源文件 003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 013 用二维数组实现矩阵转置 014 求解二维数组的最大/最小元素 015 利用数组求前n个质数 016 编制万年历 017 对数组元素排序 018 任意进制数的转换 019 判断回文数 020 求数组前n元素之和 021 求解钢材切割的最佳订单 022 通过指针比较整数大小 023 指向数组的指针 024 寻找指定元素的指针 025 寻找相同元素的指针 026 阿拉伯数字转换为罗马数字 027 字符替换 028 从键盘读入实数 029 字符行排版 030 字符排列 031 判断字符串是否回文 032 通讯录的输入输出 033 扑克牌的结构表示 034 用“结构”统计学生成绩 035 报数游戏 036 模拟社会关系 037 统计文件的字符数 038 同时显示两个文件的内容 039 简单的文本编辑器 040 文件的字数统计程序 041 学生成绩管理程序 第二部分 数据结构篇 042 插入排序 043 希尔排序 044 冒泡排序 045 快速排序 046 选择排序 047 堆排序 048 归并排序 049 基数排序 050 二叉搜索树操作 051 二项式系数递归 052 背包问题 053 顺序表插入和删除 054 链表操作(1) 055 链表操作(2) 056 单链表就地逆置 057 运动会分数统计 058 双链表 059 约瑟夫环 060 记录个人资料 061 二叉树遍利 062 浮点数转换为字符串 063 汉诺塔问题 064 哈夫曼编码 065 图的深度优先遍利 066 图的广度优先遍利 067 求解最优交通路径 068 八皇后问题 069 骑士巡游 070 用栈设置密码 071 魔王语言翻译 072 火车车厢重排 073 队列实例 074 K阶斐波那契序列 第三部分 数值计算与趣味数学篇 075 绘制余弦曲线和直线的迭加 076 计算高次方数的尾数 077 打鱼还是晒网 078 怎样存钱以获取最大利息 079 阿姆斯特朗数 080 亲密数 081 自守数 082 具有abcd=(ab+cd)2性质的数 083 验证歌德巴赫猜想 084 素数幻方 085 百钱百鸡问题 086 爱因斯坦的数学题 087 三色球问题 088 马克思手稿中的数学题 089 配对新郎和新娘 090 约瑟夫问题 091 邮票组合 092 分糖果 093 波瓦松的分酒趣题 094 求π的近似值 095 奇数平方的有趣性质 096 角谷猜想 097 四方定理 098 卡布列克常数 099 尼科彻斯定理 100 扑克牌自动发牌 101 常胜将军 102 搬山游戏 103 兔子产子(菲波那契数列) 104 数字移动 105 多项式乘法 106 产生随机数 107 堆栈四则运算 108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异条件的数列 119 超长正整数的加法 第四部分 图形篇 120 绘制直线 121 绘制圆 122 绘制圆弧 123 绘制椭圆 124 设置背景色和前景色 125 设置线条类型 126 设置填充类型和填充颜色 127 图形文本的输出 128 金刚石图案 129 飘带图案 130 圆环图案 131 肾形图案 132 心脏形图案 133 渔网图案 134 沙丘图案 135 设置图形方式下的文本类型 136 绘制正多边形 137 正六边形螺旋图案 138 正方形螺旋拼块图案 139 图形法绘制圆

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值