前言

明天就要科协笔试了,为了避免学长学姐出一些奇奇怪怪的 C 语言内容,所以我学了一些奇奇怪怪的东西。

冷知识

左移运算

C 的标准是 类型比特数 $\le$ 移位数 是未定义行为,所以以下表达式的结果是未定义的。

1
1u << 32

另外,有符号负数的左移是未定义行为,不能说以下表达式保证得到 -2。

1
-1 << 1

逗号运算符

1
2
3
4
5
6
int main() {
int i=1;
int r=(i++,i+2);
printf("%d %d",i,r);
}
//2 4

逗号运算符的运算规则是先算前边的,然后把最后一个的结果当成这个表达式的结果返回。

二级指针不允许隐式转换

会存在安全漏洞,所以以下代码是不合法的:

1
2
char *p=NULL;
const char **q=&p;

但是一级指针是可以的。

结构体的对齐规则

每个成员按自身大小对齐,结构体整体按照最大成员大小对齐!

1
2
struct S{ char c;int x;char d;};
//sizeof(struct S)=12(原因是 int 的大小是 4),所以说offsetof(x)=4

三目运算符的隐式类型转换

1
2
3
int flag=1;
printf("%d",(flag ? -1:1u)<0);
//0

原因是这个表达式有两个分支,一个是 int 一个是 unsigned int ,这个时候会自动转化为 unsigned int,所以 flag 变成了一个极大值,那显然就不小于 0 了。

浮点数的存储方式

这里以 float 为例,它的存储逻辑是:1 位符号位,8 位数字位,23 位尾数位

VLA

可变长数组,定义大概如下,是个可变长度的,在 C17 可选的特性:

1
2
int n=3;
int a[n];

创建后是锁死的,改变 n 的值不会导致数组的大小被改变。

VLA 类型还有新的数据类型,如下:

1
int[n]

这表示一个大小为 n 的 VLA,它的sizeof 结果是 $4n$。

C 标准存储期

分为以下四种:

  1. 自动存储期:普通的函数变量
  2. 静态存储期:静态变量
  3. 分配存储期:malloc
  4. 线程存储期(考试不考!)

逻辑与和逻辑或的短路现象

1
2
int x=0;
printf("%d",(x&&(10/x)));

这个代码看似除以 0 了,但是因为 x 本身就是 0,所以已经确定这个表达式会返回 0 了,就短路掉了,后面的内容不会执行。

逻辑或运算也同理。

尾后指针

对于一个数组 T a[4] 来说:

  1. a+0 到 a+3 指向数组元素,可以解引用和读写。
  2. a+4 是合法指针,标准允许定义它、比较它、做差、当结束迭代器使用,但是不能解引用。

a+5 以后的指针直接就是未定义的野指针。

sizeof 相关

1
2
3
4
5
6
7
8
int a[4];
int *p = a;

sizeof(a) // 16:整个数组
sizeof(a[0]) // 4:一个 int
sizeof(*a) // 4:一个 int
sizeof(p) // 4 或 8:一个指针变量
sizeof(a + 0) // 4 或 8:a+0 中 a 退化,结果是指针

大端序与小端序