c语言疑难点

1,一个星号操作并一定代表一次内存寻址操作。指针指向的内存大小是指针指向的整个内存块大小,而数组变量指向的内存大小是其某个成员所占内存大小,数组变量的大小才是整个数组占用内存大小。

1
2
3
4
5
6
7
	// in x64 mode
	int a[][2] = { 5, 4, 3, 2, 1, 6 };
	int i1 = sizeof(a);		// i1 is 24
	int i11 = sizeof(*a);		// i11 is 8
	int i2 = **(a + 1);		// i2 is 3
	int i3 = **a + 1;		// i3 is 6
	int i4 = *((int*)a + 1);	// i4 is 4

对于某类型的指针p,p+1后的地址值是增加了sizeof(*p)。
对于数组a,a+1后的地址值是增加了sizeof(*a)。

2,++操作符不参入算术式内操作符之间的优化级打架,即使++操作符在括号操作符内,是不是很反直觉?

1
2
3
4
	int a[] = { 1, 2, 3, 4, 5 };
	int *p = a;
	int j = *p++; // j is 1
	int k = *(p++); // k is 2

3,关于字节对齐

1
2
3
4
5
6
struct Diamond {
	int a1;
	char a2;
	int64_t a3;
	char a4;
};

vc2019 x64和x86下都输出

1
2
3
4
5
6
7
1>class Diamond	size(24):
1> 0	| a1
1> 4	| a2
1>  	| <alignment member> (size=3)
1> 8	| a3
1>16	| a4
1>  	| <alignment member> (size=7)
1
2
3
4
5
struct Diamond {
	char a1;
	short a2;
	char a3;
};

vc2019 x64和x86下都输出

1
2
3
4
5
6
1>class Diamond	size(6):
1> 0	| a1
1>  	| <alignment member> (size=1)
1> 2	| a2
1> 4	| a3
1>  	| <alignment member> (size=1)

vector push_back后iterator还是否有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <vector>
 
using namespace std;
 
int main()
{
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vector<int>::iterator it = vec.begin();
    it++;
    for (int i = 5; i < 10000; i++)
        vec.push_back(i);
    int j = *it; //这里报错
    return 1;
}

实验证明:vector push_back后原来的iterator就失效了。

1
2
3
4
5
6
7
8
    list<int> li;
    li.push_back(1);
    li.push_back(2);
    list<int>::iterator itList = li.begin();
    itList++;
    for (int i = 5; i < 10000; i++)
        li.push_back(i);
    int result = *itList;

实验证明:list push_back后原来的iterator依然有效。
如此说明,iterator中存放的是成员的内存地址,而非成员相对基地址的位移。

UE4的TMap实现原理

TMap的成员ElementSetType是TSet类型,此TSet的成员是

1
TTuple<Key, Value>

TSet类由两个动态数组组成,一个用于Hash表,一个是TSparseArray。

先说TSparseArray,其成员Data是TArray类型,即动态数组,TSparseArray的特点是通过空闲成员内部指针将空闲成员链起来,这样可方便增加删除操作,但其中的增加操作的Index是无法预先指定的。

所以TSet类又用到了一个动态数组用于Hash表,这样可以计算Hash Key找到指定Hash表项,这个表项存的是Hash桶的最后一个入桶的成员在TSparseArray数组中的Index,而其它相同Hash Key的桶成员都在最后入桶成员结构内部链起来了。