sizeof大多数平台上 1 byte = 8 bits。
sizeof(T) 返回类型 T 占用的字节数。
sizeof() 的返回类型是 size_t。(后续讲解),其转换说明符为 %zu:printf("%zu\n", sizeof(double));
若 MinGW 对 %zu 有问题,可转为 int 并使用 %d:
printf("%d\n", (int)sizeof(double));
sizeof| 类型 | 最小宽度 | 常见宽度 |
|---|---|---|
short |
16 bits | 16 bits |
int |
16 bits | 32 bits |
long |
32 bits | 32 或 64 bits |
long long |
64 bits | 64 bits |
sizeof(signed T) == sizeof(unsigned T)sizeof(short) sizeof(int) sizeof(long) sizeof(long long)。我们知道,有限位的小数无法准确表示无限不循环小数。
例如:只用十个数,表达 1/7 只能是
同理,浮点数作为一种有限精度的二进制小数表示,会无法准确表达大量实数。
例如经典的浮点误差梗 0.1 + 0.2 != 0 .3。(实际上其结果是 0.30000000000000004)
智械入侵的时候非常有用的知识 OvO

定义函数 midpoint,接收两个浮点数并返回它们的平均值。注意选择返回类型与参数类型。
9007199254740993.0(9007199254740993.0 的平均值。这还不简单?看我轻松拿下!

拿下!
double midpoint(double a, double b) {
return (a + b) / 2.0;
}
补兑!输出居然是 9007199254740992.000000?
这是怎么回事?白毛小狗懵圈

double 使用 64 位浮点数格式:1 位符号 + 11 位指数 + 52 位尾数
浮点数误差是 不可避免(inevitable) 的,但我们可以通过一些数值技巧来减小浮点数误差带来的影响:
int isZero(double x, double eps = 1e-8) {
return (x < eps) && (x > eps);
}
int isEqual(double a, double b) {
return isZero(a - b);
}

int a = 42; double b = 3.14
a 和 b 的类型分别是什么?42 与 3.14 的类型又是什么?像 42 这样直接写在代码中的值称为 字面值(literal)。
42, 100L, 0ll, 405ul后缀:L(long)、ll(long long)、ul(unsigned long)——指示字面值的类型,大小写不敏感。
l 与大写 L(如 lL 或 Ll),统一使用 L 更清晰。若无后缀,默认类型为 int。
int 范围,会依次匹配 int → long → long long → __int128。若不支持 __int128,则这个字面值会成为一个 ill-formed(编译错误)。注意:并不存在“负字面值”。例如 -42 是对字面值 42 应用一元负号运算所得。
0xBAADF00D、052、0b101010(C23)十六进制:0x
八进制:0
二进制:0b(自 C23 起)
示例:3.14、3.14f、3.14l、1e8、3e-8
后缀 (大小写不敏感):
doublef :floatl :long double科学计数法总是浮点数。
1e8 表示 double 而不是 int。'a'、'\n'、'1'int;在 C++ 中,类型为 char。字符字面值
字符字面值是适于转换为字符类型的
int,或类型char8_t(自 C23 起)、char16_t、char32_t、wchar_t(自 C11 起)的单个字符。
char c = 'a';
c 存的是整数 97,即字符 'a' 的 ASCII 码。给定字符 'c'(且 'c' 为数字字符 '1'、'2'、…),求其对应的整数值。
c。若 c 非数字字符,行为未定义。
int)。
int charToInt(char c) {
// 检查字符是否为数字字符
if (c >= '0' && c <= '9') {
return c - '0'; // 通过减去 '0' 的ASCII值得到对应的整数
} else {
// 如果输入不是数字字符,输出错误信息并返回一个特殊值(例如 -1)
printf("错误:输入字符 '%c' 不是数字字符!\n", c);
return -1; // 返回 -1 表示错误
}
}

如果你只能用 getchar() 读取字符,如何读取一个非负整数?
getchar():参见 CppReference<ctype.h> 中的 character classification functions(字符分类函数)

f() + g() * h() 解释为 f() + (g() * h()),而非 (f() + g()) * h()。f() - g() + h() 解释为 (f() - g()) + h(),而非 f() - (g() + h())。结合性:相同优先级的运算符如何分组
左结合(Left Associativity):从左向右分组
f() - g() + h() → (f() - g()) + h()右结合(Right Associativity):从右向左分组
例如赋值运算符 =:a = b = c
a = (b = c)b = c 的结果是 b(且等于 c)a = b之前的例子 f() - g() + h()、f() - (g() + h()) 中,f()、g()、h() 的调用顺序是什么?
另例:func(f(), g(), h())
f()、g()、h() 的调用顺序同样未指定。若两个表达式 A 与 B 的求值顺序未指定,且它们:
则构成未定义行为(undefined behavior)。
例:i = i++ + 2 的结果是什么?
一旦开始分析它是 +1 还是 +2,你就掉入了未定义行为的陷阱。
++ 修改了 i,赋值也修改了 i,而两者的先后顺序未指定,因此是 undefined behavior。double pi = 3.14; printf("%d\n", pi);(类型不匹配导致 UB)在常见运算符中,只有 4 个具有确定的求值顺序:&&、||、?:、,。
&& 与 ||:短路求值(short-circuit / minimal evaluation / McCarthy evaluation)
条件运算符 cond ? t : f
cond,再根据其真假计算 t 或 f;两者只会计算其一。逗号运算符 ,
int main(void){
int a = 1;
int b = (a++, a + 100, a - 10);
}
上述程序中
b的值是多少?(提示:逗号表达式取最后一个子表达式的值)

答案上 b = -8!
a++:先使用 a 的值(1),然后 a 自增为 2a + 100:计算 2 + 100 = 102(但结果被丢弃,因为不是最后一个表达式)a - 10:计算 2 - 10 = -8,这是最后一个表达式,因此作为整个逗号表达式的值,赋值给 b所以 b 的值是 -8。
~, &, ^, |, <<, >>,以及复合赋值(compound assignment)&=, |=, ^=, <<=, >>=
| 运算符 | 名称 | 示例 | 含义 | |
|---|---|---|---|---|
~ |
按位非(NOT) | ~a |
a 的逐位取反 |
|
& |
按位与(AND) | a & b |
a 与 b 的逐位与 |
|
| ` | ` | 按位或(OR) | a | b |
a 与 b 的逐位或 |
^ |
按位异或(XOR) | a ^ b |
a 与 b 的逐位异或 |
|
<< |
左移(Left Shift) | a << i |
a 的二进制位左移 i 位 |
|
>> |
右移(Right Shift) | a >> i |
a 的二进制位右移 i 位 |
~a:把 a 的每一位都翻转。
a & b:第 i 位只有在 a 与 b 的第 i 位都为 1 时结果为 1。
a | b:第 i 位只要 a 或 b 的第 i 位至少一个为 1 时结果为 1。
a ^ b:第 i 位在 a 与 b 的第 i 位不同时结果为 1。
例:a & 1:
a 与 a % 2(取奇偶)。设 a 为无符号整数。
a << i:把 a 的二进制位左移 i 位
a << 1 等价于 a * 2;一般 a << i 等价于 a * 2^ia >> i:把 a 的二进制位右移 i 位
a >> 1 等价于 a / 2
这时候我们并没有 pow 等等指数函数!
难道要做一个循环,每次 *2 吗?
1 << n
1 是 int 字面值。n 较大,你可能需要 1u << n、1ll << n 等(以避免溢出,并同时得到期望类型)。
如何获得无符号整数 x 的第 i 位?
i ∈ [0, N),N 为 x 的类型的总比特数,0 位为最右侧(LSB)。int test_bit(unsigned x, unsigned i) {
// TODO
}
int test_bit(unsigned x, unsigned i) {
// 将 x 右移 i 位,使目标位移动到最低位
// 然后与 1 进行按位与操作,提取该位的值
return (x >> i) & 1;
}
假设 x = 13(二进制为 1101),我们想获取第2位的值:
x >> 2得到 0011(十进制为3)(x >> 2) & 1 得到 0011 & 0001 = 0001,即 1。如何翻转无符号整数 x 的第 i 位?
unsigned bit_flip(unsigned x, unsigned i) {
// TODO
}

如何翻转无符号整数 x 的第 i 位?
unsigned bit_flip(unsigned x, unsigned i) {
// 创建一个只有第 i 位为 1 的掩码,然后与 x 进行异或操作
return x ^ (1U << i);
}
1U << i:将无符号整数 1 左移 i 位,创建一个只有第 i 位为 1 的掩码x ^ mask:通过异或操作翻转第 i位
0,则 0 ^ 1 = 1(翻转)1,则 1 ^ 1 = 0(翻转)
如何从无符号整数 x 中提取位区间 [low, high)?
unsigned bit_slice(unsigned x, unsigned low, unsigned high) {
// TODO
}
提示:考虑使用 Mask!
unsigned bit_slice(unsigned x, unsigned low, unsigned high) {
// 创建一个掩码,用于提取指定的位区间
unsigned mask = (1U << (high - low)) - 1;
// 右移 x 使目标位区间对齐到最低位,然后应用掩码
return (x >> low) & mask;
}

本次 Slides 中的所有示例代码都会被 Release 在 Piazza 上。表情包暂时不 Release。