CSAPP | Bits, Bytes, and Integers

Great Reality

Ints are not Integers, Floats are not Reals

对于 (x + y) + z = x + (y + z),无符号整形和有符号整形是成立的。
但是对于浮点数, (1e20 + -1e20) + 3.14 -> 3.14,而 1.e20 + (-1e20 + 3.14) = 0

typedef struct {
	int a[2];
	double d;
}struct_t;

double fun(int i) {
	volatile struct_t s;
	s.d = 3.14;
	s.a[i] = 1073741824; /* Possibly out of bounds */
	return s.d;
}

我们发现,当 i = 5 时,程序会崩溃。

Explanation:

C 语言不会在运行中做任何边界检查
对于下图,垂直链的每个块代表 4 字节。a 数组的两个元素都是 4 字节,d 是 8 个字节

当 i 大于 1 时,赋值 a[2] 会赋值给 d3 … d0,赋值 a[3] 会赋值给 d4 … d7,所以 i = 4 的时候正常,后面报不报错看栈的空间等。

Memory System Performance Example

下面有两端函数。

void copyij(int src[2048][2048], int dst[2048][2048])
{
	int i, j;
	for(int i = 0; i < 2048; i ++)
		for(int j = 0; j < 2048; j ++)
			dst[i][j] = src[i][j];
}
void copyji(int src[2048][2048], int dst[2048][2048])
{
	int i, j;
	for(int j = 0; j < 2048; j ++)
		for(int i = 0; i < 2048; i ++)
			dst[i][j] = src[i][j];
}

可以看出它们的区别在于一个行优先,一个列优先。而第一段代码运行速度远远快于第二段代码。以行优先代码的运行速度快于一列一列运行。

Everything is bits

整数、浮点数等都可以表示为二进制。

Data Representations

C Data TypeTypical 32-bitTypical 64-bitx86-64
char111
short222
int444
long488
float444
double888
long double--10/16
pointer488

Boolean Algebra

And: A & B = 1 when both A = 1 and B = 1
Or: A | B = 1 when either A = 1 or B = 1
Not: ~A = 1 when A = 0
Exclusive-Or(Xor): A^B = 1 when either A = 1 or B = 1, but not both 相同为 0,相异为 1

Representing & Manipulating

Representation

Width w bit vector represents subsets of {0, …, w - 1}
a j = 1    i f    j    ∈ A a_j = 1~ ~if~ ~j~ ~\in A aj=1  if  j  A

01101001 代表 {0, 3, 5, 6}
76543210

01010101 代表 {0, 2, 4, 6}
76543210

Operations
符号操作二进制序列集合
&Intersection 交01000001{0, 6}
|Union 并01111101{0, 2 ,3, 4, 5, 6}
^Symmetric difference 对称差异00111100{2, 3, 4, 5}
~Complement 补10101010{1, 3, 5, 7}

Bit-Level Operations in C

位运算

Examples(Char data type)

∼ 0 x 41 − > 0 x B E \sim0x41 -> 0xBE 0x41>0xBE
∼ 0100000 1 2 − > 1011111 0 2 \sim01000001_2->10111110_2 010000012>101111102

∼ 0 x 00 − > 0 x F F \sim0x00 -> 0xFF 0x00>0xFF
∼ 0000000 0 2 − > 1111111 1 2 \sim0000 0000_2->1111 1111_2 000000002>111111112

∼ 0 x 69    &    0 x 55 − > 0 x 41 \sim0x69~ ~\&~ ~0x55 -> 0x41 0x69  &  0x55>0x41
$\sim0110 1001_2 $ & \& & 0101010 1 2 − > 0100000 1 2 0101 0101_2->0100 0001_2 010101012>010000012

∼ 0 x 69    ∣    0 x 55 − > 0 x 7 D \sim0x69 ~~| ~~0x55 -> 0x7D 0x69    0x55>0x7D
∼ 0110100 1 2 \sim 01101001_2 011010012 ∣ | 0101010 1 2 − > 0111110 1 2 01010101_2 -> 01111101_2 010101012>011111012​​​

Logic Operations in C

& & , ∣ ∣ , ! \&\&, ||, ! &&,∣∣,!
view 0 as “False”
Anythings nonzero as “True”
Always return 0 or 1
Early termination
C 语言的逻辑运算只有 2 种结果, 0x00 和 0x01
取反是按结果取反,不是按位取反!

Examples(Char data type)

! 0 x 41 − > 0 x 00 !0x41 -> 0x00 !0x41>0x00 相当于对 true 取反,结果为 false, 为 0x00
! 0 x 00 − > 0 x 01 !0x00 -> 0x01 !0x00>0x01
! ! 0 x 41 − > 0 x 01 !!0x41-> 0x01 !!0x41>0x01

0 x 69    & &    0 x 55 − > 0 x 01 0x69~ ~\&\&~ ~0x55 -> 0x01 0x69  &&  0x55>0x01
0 x 69    ∣ ∣    0 x 55 − > 0 x 01 0x69~ ~||~ ~0x55 -> 0x01 0x69  ∣∣  0x55>0x01
p    p~~ p   & & \&\& && ∗ p *p p (avoids null pointer access) 在访问之前先判断是否为空指针,如果是空指针,会提前终止。

Shift Operation

Left Shift: x << y

Shift bit-vector x left y positions, Throw away extra bits on left
Fill with 0’s on right

Right Shift: x >> y

Shift bit-vector x right y position, Throw away extra bits on right
Logical Shift
Fill with 0’s on left
Arithmetic Shift
Replicate(复制) most significant bit on left
对于右移运算,分为算数右移和逻辑右移。他们的填充规则不一样。算数右移填充的是符号位的数字。

Argument x0110 0010
<< 30001 0000
Log. >> 20001 1000
Arith. >> 20001 1000
Argument x1010 0010
<< 30001 0000
Log. >> 20010 1000
Arith. >> 21110 1000
Undefined Behavior

Shift amount < 0 or >= word size

Numeric Ranges

Unsigned Values

U M i n = 0 − > 000...0 UMin = 0 -> 000...0 UMin=0>000...0
U M a x = 2 w − 1 − > 111...1 UMax = 2^w - 1 -> 111...1 UMax=2w1>111...1
U M a x = 2 × T M a x + 1 UMax = 2 \times TMax + 1 UMax=2×TMax+1

Two’s Complement Values (补码)

T M i n = − 2 w − 1 − > 100...0 TMin = -2^{w - 1} -> 100...0 TMin=2w1>100...0
T M a x = w w − 1 − 1 − > 011...1 TMax = w^{w - 1} - 1 -> 011...1 TMax=ww11>011...1
∣ T M i n ∣ = T M a x + 1 |TMin| = TMax + 1 TMin=TMax+1

Other Values

M i n u s   1 − > 111...1 Minus~1 -> 111...1 Minus 1>111...1

Values for W = 16
DecimalHexBinary
UMax65535FF FF11111111 11111111
TMax327677F FF01111111 11111111
TMin-3276880 0010000000 00000000
-1-1FF FF11111111 11111111
0000 0000000000 00000000
U M a x = 2 × T M a x + 1 UMax = 2 \times TMax + 1 UMax=2×TMax+1
From Binary to Unsigned

B 2 U ( X ) = ∑ i = 0 w − 1 x i 2 i B2U(X) = \sum_{i = 0}^{w - 1}x_i 2^i B2U(X)=i=0w1xi2i

From Binary to Two’s complement

B 2 T ( X ) = − x w − 1 2 w − 1 + ∑ i = 0 w − 2 x i 2 i B2T(X) = -x_{w - 1} 2^{w - 1} + \sum_{i = 0}^{w - 2} x_i 2^i B2T(X)=xw12w1+i=0w2xi2i
对于补码,最高位称为符号位,为 1 代表负数。

Unsigned & Signed Numeric Values
XB2U(X)B2T(X)
000000
000111
001022
001133
010044
010155
011066
011177
10008-8
10019-7
101010-6
101111-5
110012-4
110113-3
111014-2
111115-1
观察可知,负数与对应的正数关系是,正数取反加 1
Casting

如果有符号数和无符号数混合,有符号数会被隐式转换为无符号数。
− 1 > 0 U -1 > 0U 1>0U 因为 − 1 -1 1 会被转换为无符号数 1111    1111 1111~ ~1111 1111  1111 也就变成 U M a x UMax UMax
W = 32 ,   T M I N = − 2147483647 ,   T M A X = 2147483647 W =32,~TMIN = -2147483647, ~TMAX=2147483647 W=32, TMIN=2147483647, TMAX=2147483647
2147483647 U < − 2147483647 − 1 2147483647U < -2147483647 - 1 2147483647U<21474836471
( u n s i g n e d ) − 1 > − 2 (unsigned)-1 > -2 (unsigned)1>2
2147483647 < 2147483648 U 2147483647 < 2147483648U 2147483647<2147483648U
2147483647 > ( i n t ) 2147483648 U 2147483647 > (int)2147483648U 2147483647>(int)2147483648U, 对于 32 位系统来说, i n t int int 范围是 − 2147483648 ∼ 2147483647 -2147483648 \sim 2147483647 21474836482147483647, u n s i g n e d   i n t unsigned~int unsigned int 范围是 0 ∼ 4294967295 0 \sim 4294967295 04294967295,所以将 2147483648 U 2147483648U 2147483648U 转换为 i n t int int, 会溢出。

考虑以下的代码:
对于 x = TMin, 他的输出还是 TMin。
因为 − x = ∼ x + 1 -x = \sim x + 1 x=∼x+1
对于 TMin 1000…0 取反 0111…1 再加 1, 1000…0 所以结果还是 TMin

if(x < 0)
	return -x;
else
	return x;

以下代码会造成无限循环。 i i i 会从 0 0 0 变为 U M a x UMax UMax (个人认为是 0 减 1 为 -1, 表示为全 1,则解释为 UMax)

unsigned int i;
for(i = n - 1; i >= 0; i --) {
	f(a[i]);
}

对于下面的代码, s i z e o f ( c h a r ) sizeof(char) sizeof(char) 实际上返回的是 无符号数。 i i i 为有符号数,有符号数和无符号数比较会被转换为无符号数。 i − s i z e o f ( c h a r ) > = 0 i - sizeof(char) >= 0 isizeof(char)>=0 这个条件就会一直成立,无限循环。

int i;
for(i = n - 1; i - sizeof(char) >= 0; i --) {
	f(a[i]);
}

Sign Extension

Task:
Given w-bit signed integer x
Convert it to (w+k)-bit integer with same value
Rule:
Make k copies of sign bit
X ′ = x w − 1 , . . . , x w − 1 , x w − 2 , . . . , x 0 X' = x_{w-1}, ..., x_{w-1}, x_{w - 2}, ..., x_0 X=xw1,...,xw1,xw2,...,x0
对于 1110 1110 1110,符号位权重为 − 2 3 = − 8 -2^3=-8 23=8,将它左移一位,变为 11110 11110 11110,原先符号位位置上的权重变为了 8 8 8,而新的符号位权重为 − 2 4 = − 16 -2^4=-16 24=16, − 16 + 8 = − 8 -16 + 8 = -8 16+8=8, 所以并不改变总和的效应。
Converting from smaller to larger integer data type, C automatically performs sign extension.

short int x = 15213;
int ix = (int) x;
short int y = -15213;
int iy = (int) y;

image.png

Two’s Complement Addition

-5 + 3
1011
+0011
1110 -> -2

-3 + 5
1101
+0101
10010 -> 0010 -> 2

-3 + -5
1101
+1011
10000 -> 0 负溢出

位运算

移位指令比乘法指令花的时间更少。
u < < k u << k u<<k 相当于 u × 2 k u \times 2^k u×2k
u > > k u >> k u>>k 相当于 ⌊ u / 2 k ⌋ \lfloor {u / 2^k} \rfloor u/2k
前面介绍过算数右移与逻辑右移。算数右移可以保持符号位。例如 1010 为 -6,算数右移 1 位,则为 1101 为 -3。但是此时如果再右移 1 位,得到 1110 为 -2。结果出现问题。
特别的,对于负数的除法,如果需要右移 k k k 位,我们需要先加上偏移量 2 k − 1 2^k - 1 2k1
1101 + 1 = 1110 此时再右移 1 位,得到 1111 为 -1。

正数变负数

x − > − x x -> -x x>x 需要对所有位取反,再 + 1。
0101 -> 5
1010 + 1 = 1011 -> -5

使用 Unsigned 一些方式

unsigned i;
for(i = cnt - 2; i < cnt; i --)
	a[i] += a[i + 1];

Better Version:

size_t i;
for(i = cnt - 2; i < cnt; i --)
	a[i] += a[i + 1];
/*
1. Data type size_t defined as unsigned value with length = word size
2. Code will work even if cnt = UMax
*/

然而,当 cnt 为 signed 并且小于 0 时。会有问题。cnt 会被转换为无符号数,就会变得非常大,导致无限循环。

大端序和小端序

Big Endian

高位字节存入低地址,低位字节存入高地址。

上图从左往右 01234567

Little Endian

低位字节存入低地址,高位字节存入高地址。

从右往左 01234567

字符串

字符串以 null 结尾,也就是 ‘0’

char S[6] = '18213';

字符 ‘0’ 为 0x30,数字字符 i 为 0x30 + i
对于字符串数组来说,大端法和小端法存储没有区别。因为字符是一个字节一个字节存储,而每个都是一个整体。

[!NOTE]
例如对于 0x12345678 来说,这是一个整体,0x12 是整体的高位,0x78 是整体的低位,存储就是 0x78 0x56 0x34 0x12。而对于字符数组,内部组织形式是一个字节一个字节,数组相当于是 0x12 0x34 0x56 0x78,每个字符是一个整体。

易错

1.如果 x < 0, 那么 ( ( x ∗ 2 ) < 0 ) ((x * 2) < 0) ((x2)<0) 吗? 错误,因为可能会负溢出, x ∗ 2 x * 2 x2 可能会是一个正数。

2.如果一个数 x,x & 7 == 7,也就是最低的 3 位为 111,如果 (x << 30) 那么结果 < 0。

3.Is ux > -1? 错的。无符号数和有符号数作比较,有符号数被隐式转换为无符号数。-1 就会被转换为 UMax。

4.如果 x > y,那么 -x < -y 一定成立吗? 错误的,因为如果 y 为 TMin,我们直到 ∣ T M i n ∣ = T M a x + 1 |TMin| = TMax + 1 TMin=TMax+1。对 TMin 取相反数,也就是 TMin 的位取反再 + 1,那就变成 TMax + 1,发生正溢出。又变回了 TMin。

5.x >= 0 那么 -x <= 0 吗? 正确的

6.x <= 0 那么 -x >= 0 吗? 错误的,比如 TMin。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/586142.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode】拓扑排序——课程表 I II

拓扑排序&#xff1a; AOV网&#xff1a;若用DAG图&#xff08;有向无环图&#xff09;表示一个工程&#xff0c;其顶点表示活动&#xff0c;用有向边<Vi, Vj>表示活动Vi必须先于活动Vj进行的这样一种关系&#xff0c;则将这种有向图称为顶点表示活动的网络&#xff0c;…

JSP:操作指令

目录 目录 一、jsp:useBean操作 语法格式&#xff1a; 属性说明&#xff1a; scope作用域&#xff1a; 1.page&#xff1a; 2.request&#xff1a; 3.session&#xff1a; 4.application 案例&#xff1a;JavaBean的简单使用 二、jsp:setProperty操作 语法格式&a…

【记录】Python3| 将 PDF 转换成 HTML/XML(✅⭐⭐⭐⭐pdf2htmlEX)

本文将会被汇总至 【记录】Python3&#xff5c;2024年 PDF 转 XML 或 HTML 的第三方库的使用方式、测评过程以及对比结果&#xff08;汇总&#xff09;&#xff0c;更多其他工具请访问该文章查看。 文章目录 pdf2htmlEX 使用体验与评估1 安装指南2 测试代码3 测试结果3.1 转 HT…

jenkins转载文本

基于Docker容器DevOps应用方案 企业业务代码发布系统 一、企业业务代码发布方式 1.1 传统方式 以物理机或虚拟机为颗粒度部署部署环境比较复杂&#xff0c;需要有先进的自动化运维手段出现问题后重新部署成本大&#xff0c;一般采用集群方式部署部署后以静态方式展现 1.2 容…

ubuntu部署sonar与windows下使用sonar-scanner

ubuntu部署sonar与windows下使用sonar-scanner sonar部署java安装mysql安装配置sonarqube 插件安装sonar-scanner使用简单使用 sonar部署 使用的是sonarqube-7.5&#xff0c;支持的java环境是jdk8&#xff0c;且MySQL版本 >5.6 && <8.0 java安装 打开终端&…

为什么3D模型材质是透明的?---模大狮模型网

在进行3D建模和渲染过程中&#xff0c;正确的材质设置是保证模型外观逼真和渲染效果良好的关键之一。然而&#xff0c;有时您可能会遇到3D模型材质变成透明的情况&#xff0c;这可能会导致意想不到的效果和渲染结果。本文将探讨一些可能导致3D模型材质变成透明的原因&#xff0…

Go中为什么不建议用锁?

Go语言中是不建议用锁&#xff0c;而是用通道Channel来代替(不要通过共享内存来通信&#xff0c;而通过通信来共享内存)&#xff0c;当然锁也是可以用&#xff0c;锁是防止同一时刻多个goroutine操作同一个资源&#xff1b; GO语言中&#xff0c;要传递某个数据给另一个gorout…

亚马逊关键字搜索商品列表API接口:探索海量商品的利器

亚马逊关键字搜索商品列表API接口允许开发者通过输入关键字或特定参数&#xff0c;在亚马逊平台上进行商品搜索&#xff0c;并返回符合搜索条件的商品列表信息。这些信息包括商品的标题、图片、价格、评价等&#xff0c;为商家、开发者以及市场分析师提供了丰富的商品数据支持。…

Aker(安碁科技)晶振产品应用和选型

一、石英晶体振荡器简介 在电子电路系统中&#xff0c;特定的动作需要严格按照一定的顺序进行&#xff0c;以确保数据被正确处理和操作&#xff0c;时钟信号就成了系统工作的重要引导者。而且在多模块复杂电路系统中&#xff0c;为了确保不同功能模块能协调一致地工作&#xf…

C#调用skiasharp操作并绘制图片

之前学习ViewFaceCore时采用Panel控件和GDI将图片及识别出的人脸方框和关键点绘制出来&#xff0c;本文将其修改为基于SKControl和SKCanvas实现相同的显示效果并支持保存为本地图片。   新建Winform项目&#xff0c;在Nuget包管理器中搜索并安装一下SkiaSharp和ViewFaceCore…

三维SDMTSP:GWO灰狼优化算法求解三维单仓库多旅行商问题,可以更改数据集和起点(MATLAB代码)

一、单仓库多旅行商问题 多旅行商问题&#xff08;Multiple Traveling Salesman Problem, MTSP&#xff09;是著名的旅行商问题&#xff08;Traveling Salesman Problem, TSP&#xff09;的延伸&#xff0c;多旅行商问题定义为&#xff1a;给定一个&#x1d45b;座城市的城市集…

springboot 集成 flowable

随着企业对于业务流程管理需求的增加&#xff0c;流程引擎在企业信息化建设中的作用越来越重要。Flowable是一个开源的轻量级业务流程管理&#xff08;BPM&#xff09;和工作流引擎&#xff0c;它支持BPMN 2.0标准。 Flowable的一些特点&#xff1a; 安装集成&#xff1a;Flow…

hdfs安全模式

hdfs安全模式 1.安全模式 查看hdfs是否在安全模式&#xff1a;不能上传数据 删除 修改 但是能查看 ------------------------ $>hdfs dfsadmin -safemode enter //进入 $>hdfs dfsadmin -safemode get //查看 $>hdfs dfsadmin -saf…

巧用 TiCDC Syncpiont 构建银行实时交易和准实时计算一体化架构

本文阐述了某商业银行如何利用 TiCDC Syncpoint 功能&#xff0c;在 TiDB 平台上构建一个既能处理实时交易又能进行准实时计算的一体化架构&#xff0c;用以优化其零售资格业务系统的实践。通过迁移到 TiDB 并巧妙应用 Syncpoint&#xff0c;该银行成功解决了原有多个 MySQL 集…

解决TIVA飞控玄学类问题的通解,用魔法打败魔法

问题&#xff1a;我遭遇了玄学问题&#xff0c;出现飞机在起降过程中&#xff0c;位置晃动&#xff0c;突然出现的&#xff0c;昨天还好好的&#xff0c;位置地点都没换&#xff0c;今天中午测试了5、6次每次都这样&#xff0c;现在茫然无措&#xff0c;小哥救我&#xff1f; 这…

数据库管理-第179期 分库分表vs分布式(20240430

数据库管理179期 2024-04-30 数据库管理-第179期 分库分表vs分布式&#xff08;20240430&#xff09;1 分库分表1.1 分库1.2 分表1.3 组合1.4 问题 2 分布式3 常见分布式数据库4 期望总结 数据库管理-第179期 分库分表vs分布式&#xff08;20240430&#xff09; 作者&#xff1…

vue路由(路由基本使用,传参,多级路由)

目录 vue-router简介路由配置和使用嵌套&#xff08;多级&#xff09;路由路由传参方式1&#xff1a;路由的query参数方式2&#xff1a;路由的params参数props配置 命名路由取消路由组件在前进后退 vue-router简介 vue的一个插件库&#xff0c;专门用来实现SPA应用 路由配置…

k8s环境prometheus operator监控集群外资源

文章目录 k8s环境添加其他节点基于prometheus operator k8s环境prometheus operator添加node-exporter方式一&#xff1a;通过 ServiceMonitor 方式可以写多个监控node节点运行 external-node.yaml查看资源有没有被创建热更新 外部需要被监控服务器安装 node-exporterdocker 方…

git如何将多个commit合并成一个?

我们使用git进行版本控制&#xff0c;在本地开发完某个功能时&#xff0c;需要提交commit&#xff0c;然后push至开发分支。简单的功能还好&#xff0c;几个commit可能就好了。但是如果功能比较复杂&#xff0c;commit多达十几甚至几十个时&#xff0c;commit管理就会很冗长。比…

使用Pandas和Matplotlib实现数据探索性可视化

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 使用 Pandas 和 Matplotlib 实现数据探索性可视化 在数据分析和机器学习领域&#xff0c;数…