c/c++ 有符号数与无符号数的转换

在开发中,经常会碰到有符号数与无符号数之间的转换,有时是隐性,有时是显性。如果不清楚其中规则,则可能带来非常难以排查的bug。

下图表示几个常用的数据类型之间的转换:


注:

  1. 上表中使用大端格式表示数据
  1. 上表中的数据为16进制

 

x表示转换前后的变量的值本身不发生变化,而解析方式改变(解析为有符号数或无符号数)

e:表示将发生零扩展(在开头填0

E:表示将发生符号扩展(填充最高有效位的值

c:表示将发生截断,保留低位,多余的高位舍去


废话少说,show the code:

/*
 * HOST: Linux 3.2.0-4-686-pae #1 SMP Debian 3.2.60-1+deb7u1 i686 GNU/Linux
 * GCC: Thread model: posix, gcc version 4.7.2 (Debian 4.7.2-5)
 * INFO: The basic data type conversion between signed and unsigned.
 *
 * */

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char uchar;
typedef unsigned int uint;
typedef uchar * byte_pointer;

void show_bytes(byte_pointer addr, int size)
{
        int i = 0;

        for (i = 0; i < size; i++) {
                printf("%02x", addr[i]);
                if (i != size - 1)
                        printf(" ");
        }
        printf("\n");
}

int item_counter;
struct test_item {
        char *name;
        char buf[8];
        int len;
        byte_pointer p;
};

struct test_item *menu[100];

#define ITEM_ADD(f, t, d)                                                       \
        do {                                                                    \
                struct test_item *p;                                            \
                p       = (struct test_item*)malloc(sizeof(struct test_item));  \
                p->name         = #f"("#d") to "#t;                             \
                p->len          = sizeof(t);                                    \
                *(t*)p->buf     = (f)d;                                         \
                menu[item_counter++]    = p;                                    \
        }while(0)


int main(void)
{
        ITEM_ADD(char,  int,    0x5f);
        ITEM_ADD(char,  int,    0xff);
        ITEM_ADD(char,  uint,   0x5f);
        ITEM_ADD(char,  uint,   0xff);
        ITEM_ADD(uchar, int,    0x5f);
        ITEM_ADD(uchar, int,    0xff);
        ITEM_ADD(uchar, uint,   0x5f);
        ITEM_ADD(uchar, uint,   0xff);
        ITEM_ADD(int,   char,   0x5f);
        ITEM_ADD(int,   char,   0xffffffffu);
        ITEM_ADD(int,   uchar,  0x5f);
        ITEM_ADD(int,   uchar,  0xfffffffu);
        ITEM_ADD(uint,  char,   0x5f);
        ITEM_ADD(uint,  char,   0xfffffffu);
        ITEM_ADD(uint,  uchar,  0x5f);
        ITEM_ADD(uint,  uchar,  0xffffffu);

        int j;
        for (j = 0; j < item_counter; j++) {
                printf("%-28s", menu[j]->name);
                show_bytes((byte_pointer)menu[j]->buf, menu[j]->len);
                free(menu[j]);
        }

        return 0;
}

输出结果(主机环境为小端格式,32位):


总结:

有符号的占用空间小的数据类型(比如char)转换到无符号或有符号的占用空间更大的数据类型(比如int,unsigned int)会进行符号扩展,也就是在多出来的高位全部用符号位填充。示例中的char(0xff),符号位为1,为负数,故转换为int、uint的结果都是0xff ff ff ff。char(0x5f)为正数,符号位为0,转换后值不变。占用空间大的数据类型转为占用空间小的数据类型时,只取低位,高位会被截断。其余情况下,内存单元中的值不会发生变化,比如char转为uchar,只是解析方式发生改变。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值