有符号数与无符号数详解

该文章已生成可运行项目,

有符号数与无符号数

符号转换:C语言允许在各种不同的数字数据类型之间做强制类型转换,强制类型转换的结果保持位值不变,只是改变了解释这些位的方式,C语言支持所有整型数据类型的有符号和无符号运算,大多数数字都默认为是有符号的,要创建一个无符号常量,必须加上后缀字符U。

​
short    int y = -12345;


unsigned short uv = (unsigned short) v;


printf("v = %d, uv = %u\n", v, uv);

​

当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么C语言会 隐式地将有符号参数强制类型转换为无符号数,并假设这两个数都是非负的,来执行这个运算。对于像<和>这样的关系运算符来说,会导致非直观的结果。

扩展数位:不同字长的整数之间转换,同时又保持数值不变。

将一个无符号数转换为一个更大的数据类型,我们只需要简单地在表示的开头添加0,这种运算称为零扩展。

将一个补码数字转换 为一个更大的数据类型可以执行符号扩展,添加最高有效位的值。位向量[101]表示值-4+1=-3。对它应用符号扩展,得到位向量[1101],表示的值-8 + 4+1 =-3。我们可以看到,对于w=4,最高两位的组 合值是-8+4=-4,与w=3时符号位的值相同。

当把short转换成unsigned时,我们先要改变大小,之后再完成从有符号到无符号的转换。

补充:Tmin的特殊写法,TMin32写成-2147483647-1, 补码表示的不对称性和C语言转换规则之间这种奇怪的交互,迫使我们用这种 不寻常的方式来写TMin32

limits.h头文件

/* Minimum and maximum values a ‘signed int’ can hold. */

#define INT.MAX 2147483647

#define INT.MIN (-INT_MAX - 1)

截断:将-一个w位的数截断为一个k位数字时,我们会丢弃高w-k位,

函数getpeername的安全漏洞:

代码的简化版本如下:

/*

* Illustration of code vulnerability similar to that found in

* FreeBSD * s implementation of getpeername()

*/

/* Declaration of library function memcpy */

void *memcpy(void *dest, void *src, size_t n);

/* Kernel memory region holding user-accessible data */

#define KSIZE 1024;

char kbuf[KSIZE];

/* Copy at most maxlen bytes from kernel region to user buffer .*/

int copy_from_kernel(void *user_dest, int maxlen) {

/* Byte count len       is minimiim of    buffer    size and maxlen */

int len = KSIZE <maxlen ? KSIZE:maxlen;

memcpy(user.dest,    kbuf, len);

return len;

}

第7行给出的是库函数memcpy的原型,这个函数是要将一段指定长度为n 的字节从存储器的一个区域复制到另一个区域。函数copy_from_kernel 要将一些操作系统内核维护的数据复制到指定的用户可以访问的存储器区域。

调用copy_from_kernel的代码中对maxlen使用了负数值,那么,第16行的最小值计算会把这个值赋给Len,然后,Len会作为参数n被传递 给memcpy,参数n是被声明为数据类型size_t的。这个数据类型是在库文件 stdio.h中(通过typedef)被声明的。在32位机器上被定义为unsigned int。参数n是无符号的, memcpy会把它当作一个非常大的正整数,并且试图将这样多字节的数据从内核区域复制到用户的缓冲区。虽然复制这么多字节,实际上不会完成, 因为程序会遇到进程中非法地址的错误,但是程序还是能读到没有被授权的内核存储器区域。避免这类错误的一种方法就是绝不使用无符号数。实际上,除了 C 以外,很少有语言支持无符号整数。

练习:

答案:

x

二进制

T2U4(x)

-8

1000

8

-3

1101

13

-2

1110

14

-1

1111

15

0

0000

0

5

0101

5

答案:将十进制化为补码形式再以无符号的形式解读

答案:

无符号数,1

有符号数,1

无符号数,0

有符号数,1

无符号数,1

答案: A=-8+3=-5

             B=-16+8+3=-5

             C=-32+16+8+3=-5

答案:

w

fun1(w)

fun2(w)

0x00000076

0x00000076

0x00000076

0x87654321

0x00000021

0x00000021

0x000000c9

0x000000c9

0xFFFFFFc9

0xEDCBA987

0x00000087

0xFFFFFF87

答案:

无符号:0,2,1,3,7

补码:0,2,1,3,-1

答案:因为i会转换为无符号数,则i的值永远大于0,将length设置为signed。

答案:

A:当有符号数与无符号数进行比较是会产生不正确的结果。

B:因为有符号数会转换为无符号数,其值非我们的预设值。

C:将size_t设置为int。

本文章已经生成可运行项目
### Verilog 中有符号数无符号数转换方法 在 Verilog 中,可以通过显式声明 `signed` 或者通过逻辑操作实现有符号数无符号数之间的转换。以下是具体的转换方式及其示例。 #### 1. **有符号数无符号数** 当一个变量被定义为有符号数 (`signed`) 并需要作为无符号数计算时,可以将其重新赋值给一个未声明为 `signed` 的寄存器或者 wire 类型变量[^2]。这种情况下,默认行为会将该值视为无符号数处理。 ```verilog reg signed [7:0] a_signed; // 定义一个8位带符号数 reg [7:0] a_unsigned; // 定义一个8位不带符号数 initial begin a_signed = -5; // 设置a_signed为-5 (二进制表示为1111_1101) a_unsigned = a_signed; // 将a_signed赋值给a_unsigned end ``` 在此例子中,`a_signed` 值 `-5` 对应的二进制形式为 `1111_1101`。当它被赋予 `a_unsigned` 后,在后续任何涉及 `a_unsigned` 的运算中都会被视为无符号数 `251` 处理[^4]。 #### 2. **无符号数有符号数** 如果要将一个无符号数转化为有符号数,则可以直接将其赋值给一个带有 `signed` 关键字的变量。此时需要注意的是,转化后的数值解释取决于最高位的状态——如果是 `1`,则会被认为是一个负数并按照补码规则解析;反之亦然。 ```verilog reg [7:0] b_unsigned; // 定义一个8位不带符号数 reg signed [7:0] b_signed; // 定义一个8位带符号数 initial begin b_unsigned = 251; // 设定b_unsigned为251 (二进制表示为1111_1101) b_signed = b_unsigned; // 将b_unsigned赋值给b_signed end ``` 在这个场景下,虽然原始值 `251` 是作为一个正整数输入进去的,但由于它的二进制表现形式是以高位置一开头(`1111_1101`),所以在经过上述过程之后,最终存储于 `b_signed` 变量里的实际含义就变成了 `-5`。 #### 使用 `$signed()` 和 `$unsigned()` 为了更清晰地控制数据类型的转换以及避免潜在错误,推荐利用内置函数 `$signed()` 和 `$unsigned()` 来完成这些任务: - `$signed(expression)`:强制把 expression 当作有符号数来对待; - `$unsigned(expression)`:强制把 expression 当作无符号数来看待。 下面给出一段综合运用的例子: ```verilog module sign_conversion; reg [7:0] c_unsigned; reg signed [7:0] d_signed; initial begin c_unsigned = 8'b1111_1101; // 输入无符号数251 // 输出c_unsigned按无符号解读的结果 $display("Unsigned value of c_unsigned is %d", $unsigned(c_unsigned)); // 转换有符号数后再显示结果(-5) $display("Signed interpretation of c_unsigned is %d", $signed(c_unsigned)); d_signed = -5; // 初始化d_signed=-5 // 显示d_signed按有符号解读的结果(-5) $display("Value of d_signed as signed is %d", $signed(d_signed)); // 强制以无符号方式展示d_signed的内容(251) $display("Value of d_signed as unsigned is %d", $unsigned(d_signed)); end endmodule ``` 以上代码片段展示了如何分别采用 `$signed()` 和 `$unsigned()` 函数对同一组比特序列作出不同方向上的语义诠释,并打印相应的观察结果。 --- ###
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值