C语言打印16进制出现0xffffff现象的问题剖析!

  今天在博问里面看到一个朋友的问题,大致是在网络程序中,打印出来的16进制数,莫名的出现ffffff。例如,某个byte真是值为0xc9,打印出来确是0xffffffc9。原博问连接如下:http://q.cnblogs.com/q/71073/

  其实类似的问题不是只在网络程序中才会出现的,看示例代码:

  1 #include <stdio.h>
  2 int main()
  3 {
  4     char c = 0xc9;
  5     printf("A:c = %2x\n",(unsigned char)c);
  6     printf("B:c = %2x\n",c & 0xff);
  7     printf("C:c = %2x\n",c);
  8     return 0;
  9 }

  程序输出如下:

A:c = c9
B:c = c9
C:c = ffffffc9

  可以看到:

  把c转换成unsigned char打印是正确的。视作情况A。

  把c与 0xff做&操作后打印正确。视作情况B。

  对c不做任何处理,则问题复现了,打印出ffffffc9。视作情况C。

  情况A B是我百度来的一些解决C现象的方法。那么我们现在来逐一分析解释ABC三种情况。

  

  首先我们必须知道,printf()函数的%x(X)输出的是Int型别的16进制格式。所以char型别的c变量会被转换成Int型别。

  其次,我们的知道计算机是用补码表示数据的。关于原码,反码,补码的知识请自行充电。

情况C:

   c的补码:11001001(0xc9)。

   c的反码:11001000(0xc9)。

   c的原码:10110111(0xc9)。 

   因为char型别是带符号的,所以最高位的1这里视为负号。

   把c转换成Int型别   char  -----> Int

   Int_c的原码:10000000 00000000 00000000 00110111(把c原码的最高位1  提到最高位。其余高位补0)。

   Int_c的反码:11111111 11111111 11111111 11001000

   Int_c的补码:11111111 11111111 11111111 11001001(0xffffffc9)。

   所以打印出来看似诡异的值其实是合情合理的。如何避免?看AB情况。

情况B:

  我们在情况C的基础上将c与0xff做&操作。

  Int_c的补码:11111111 11111111 11111111 11001001(0xffffffc9)。

         &

         00000000 00000000 00000000 11111111

  最终结果为: 00000000 00000000 00000000 11001001(0xc9)。

情况A:

  我觉得情况A的处理方式才是最正规的处理办法,但是据说linux内核使用(&0xff)。

   c的补码:11001001(0xc9)。

   c的反码:11001001(0xc9)。

   c的原码:11001001(0xc9)。 

   这里强制转换c为unsigned char型别。因此最高位的1不是正负号

   把c转换成Int型别   char  -----> Int

   Int_c的原码:00000000 00000000 00000000 11001001(把c原码的最高位1  提到最高位。其余高位补0)。

   Int_c的反码:00000000 00000000 00000000 11001001

   Int_c的补码:00000000 00000000 00000000 11001001(0xc9)。

   因此打印正常。

  以上分析,如有不正确的地方请各位指正。

时间: 2024-08-07 00:15:06

C语言打印16进制出现0xffffff现象的问题剖析!的相关文章

C语言将16进制的数转换为字符串的方法(改进)

昨天写了一个方法,可以将嵌入式C常用的uint8_t数据转为一个字符,但是程序有警告,尴尬症发作甚是不爽,于是在今天解决了这个问题.昨天的博文 C语言中的char是一字节,也就是8个二进制位,正好可以表示成2个16进制的数.但是第一位是符号位,而单片机用的C语言中常常不牵扯负数,所以更常见的就是使用无符号的char(unsigned char),再定义为uint8_t(typedef unsigned char uint8_t;),这样子就可以用8个二进制位表示成2个16进制的数,如1111 1

C语言将16进制的数转换为字符串的方法

今天在写代码的时候遇到一个需求:为了与同一产品中的其它设备统一,上位机要求处理字符串,而不是数组.我们都知道在处理数据的时候数组方便,不过考虑到兼顾别的设备(没错我说的就是TI430做的RFID读卡设备,跟上位机之间的协议传递的是字符串/大笑),就尝试了将16进制的数据改为字符串,也就是0xAB,改成"AB"...虽然看上去没什么用. 原先的数据类型是uint8_t,熟悉单片机的都知道这个的含义,其实也就是unsigned char ,说到底还是个char,但偏偏要求表示成'A&quo

打印内存, 打印16进制

打印内存信息 1 #include <stdio.h> 2 3 // 打印内存信息 4 void showMemoryHex(void* ptr, int size) { 5 unsigned char* bytes = (unsigned char*)ptr; 6 for (int i = 0; i < size; i++) { 7 printf(" %02x", bytes[i]); 8 } 9 } 测试 struct MyStruct { int age; ch

不同变量在内存中的存在形式(以16进制表示)

1 #include<stdio.h> 2 int main() 3 { 4 char a= -1; //1111 1111 1个字节 5 short b= -1; //1111 1111- 1111 1111 2个字节 6 int c= -1; //1111 1111- 1111 1111- 1111 1111- 1111 1111 4个字节 7 printf("%hhx\n",a); //打印1个字节 8 printf("%hx\n",b); //打

WinHex V18.7(16进制编辑器) 多国语言绿色版

软件名称: WinHex V18.7(16进制编辑器)软件语言: 简体中文授权方式: 免费试用运行环境: Win7 / Vista / Win2003 / WinXP 软件大小: 1.7MB图片预览: 软件简介:WinHex是一个非常不错的 16 进制编辑器,可以用来检查和修复各种文件.恢复删除文件.硬盘损坏造成的数据丢失等,同时它还可以让你看到其他程序隐藏起来的文件和数据 中文语言在Help菜单的Setup里面设置为Chinese即可. 软件下载页面:http://www.bkill.com/

以16进制打印出一块内存buff

如下代码(支持windows与Linux)会以[16进制][每行16字节]打印出一块内存的内容: void PrintBuffer(void* pBuff, unsigned int nLen) { if (NULL == pBuff || 0 == nLen) { return; } const int nBytePerLine = 16; unsigned char* p = (unsigned char*)pBuff; char szHex[3*nBytePerLine+1] = {0};

Linux c字符串中不可打印字符转换成16进制

本文由 www.169it.com 搜集整理 如果一个C字符串中同时包含可打印和不可打印的字符,如果想将这个字符串写入文件,同时方便打开文件查看或者在控制台中打印出来不会出现乱码,那么可以将字符串中的不可打印字符转换成16进制,此处提供一个函数供使用: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void printhex(unsigned char *src,int len) {     

16进制数据流转换成C语言数组

在开发中经常遇到以下情况,通过一些工具捕获的16进制数据,应用到代码中,比如通过Wireshark抓获的数据包,观察到的程序内存数据. 但是在开发时,不能直接使用这些数据,需要转换如下样子,才可以在代码中使用: 我写了一个小工具,可以将二进制数据流转换成数组,代码如下: // FileNameToArray.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include

C语言实现字符串中(10进制和16进制)转成十进制数

如何将字符串中的10进制数和16进制数提取出来,看以下代码: #include <stdio.h> typedef char TUINT8 ; typedef int TUINT32; TUINT32 Read_DecNumber(const TUINT8* str); TUINT32 Read_HexNumber(const TUINT8* str); int main(void) { int ret = Read_DecNumber("1000"); int d = R