了解 C++ 运算符重载
Understanding C++ operator overloading
我今天在阅读哈希竞赛的源代码时,遇到了这个:
#define BYTES_IN_BLOCK 1024
struct block{
uint8_t v[BYTES_IN_BLOCK];
block(){ memset(v, 0, BYTES_IN_BLOCK); }
uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
};
然后,稍后在代码中,有这个:
state = new block[cost]; // cost is a uint32_t (like 1024)
// Probably 50 lines of code.
block prev_block;
prev_block = state[foo]; // foo is a uint32_t
我不明白这是在做什么。现在,我了解 C,但 C++ 不是那么多。请耐心等待。
这部分:return *(uint64_t*)(v+8*i)
应该 return 一个 uint64_t
,并且在我测试它时这样做:
state->v[8*10] = 12;
uint64_t bar = *(uint64_t*)(v+8*10);
printf("%" PRIu64 "\n", bar);
所以一切都说得通了。
但是这个:
prev_block = state[foo];
没有意义。由于 state
是 block*
,prev_block
现在应该 "be" state
,对吗?但是不是,因为他们的数组不一样
state->v[8*12] = 12;
printf("%" PRIu64 "\n", (*state)[12]);
prev_block = state[12];
printf("%" PRIu64 "\n", (*(&prev_block))[12]);
那么,这里到底发生了什么?
state = new block[cost];
prev_block = state[foo];
类似于:
int* arr = new int[size];
int a = arr[index];
这是基本的 C++。我不确定为什么会造成混淆。
您混淆了此处涉及的两个 operator[]
。在上一个示例中,您设置了 state[0][12] = 12
,并将其与 state[12][12]
进行了比较。由于 state
是 block*
,state[n]
只是正常的数组访问;它不会调用 block
中定义的 operator[]
。
这里有很多概念混淆。我将对我看到的所有问题进行全面介绍,因为它们都很重要,而不仅仅是直接的答案。
state
是指向块的指针,但 state[0]
应该只是一个块,特别是状态中的第一个块,也是 *state
的结果。
prev_block = state[foo];
block中的所有数据都很简单,就是一个独立的字节数组,所以应该可以直接复制,不需要任何特殊的帮助。 prev_block = state[foo]
应该将状态 [foo] 复制到 prev_block。因为是副本,地址会不一样
在提供的打印输出代码中:
state->v[8*12] = 12;
为清楚起见,将他分解。 state->
将访问状态数组的第一个元素。 state->v[8*12]
将访问 state[0] 的 v[8*12]。 state->v[8*12] = 12;
会将 state[0] 的 v[8*12] 设置为 12。这意味着 v 的字节 96 将为 12。要引用不同的状态,您可以使用 (state + array_index)->v[8*12];
或 state[array_index].v[8*12];
我发现后者更具可读性。
printf("%" PRIu64 "\n", (*state)[12]);
(*state)
为您提供数组中的第一个状态,即 state[0]
。 (*state)[12]
使用 state[0]
的 [] 运算符,定义为 uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
这将 return 一个 64 位整数,从 state[0].v[12*8] 的地址开始,由数组 v 的下一个 8 个字节组成(v[96] 到v[103],结果为 12,0,0,0,0,0,0,0)。这将是 12 或一个非常大的数字,具体取决于系统的 endian。包装 printf 将打印 returned 数字。
prev_block = state[12];
将把状态数组的第 13 个元素复制到 prev_block,假设 state = new block[cost];
创建了足够多的块。没什么神奇的,但除了零之外不应该有任何东西,因为唯一设置了任何值的状态是 state[0]。您要么想在此处复制 state[0]
,要么写到 state[12]
上几行。
printf("%" PRIu64 "\n", (*(&prev_block))[12]);
* 和 & 在完成任何事情之前相互抵消。然后它将打印出使用 block [] 运算符的结果,如上。应该为零。
我今天在阅读哈希竞赛的源代码时,遇到了这个:
#define BYTES_IN_BLOCK 1024
struct block{
uint8_t v[BYTES_IN_BLOCK];
block(){ memset(v, 0, BYTES_IN_BLOCK); }
uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
};
然后,稍后在代码中,有这个:
state = new block[cost]; // cost is a uint32_t (like 1024)
// Probably 50 lines of code.
block prev_block;
prev_block = state[foo]; // foo is a uint32_t
我不明白这是在做什么。现在,我了解 C,但 C++ 不是那么多。请耐心等待。
这部分:return *(uint64_t*)(v+8*i)
应该 return 一个 uint64_t
,并且在我测试它时这样做:
state->v[8*10] = 12;
uint64_t bar = *(uint64_t*)(v+8*10);
printf("%" PRIu64 "\n", bar);
所以一切都说得通了。
但是这个:
prev_block = state[foo];
没有意义。由于 state
是 block*
,prev_block
现在应该 "be" state
,对吗?但是不是,因为他们的数组不一样
state->v[8*12] = 12;
printf("%" PRIu64 "\n", (*state)[12]);
prev_block = state[12];
printf("%" PRIu64 "\n", (*(&prev_block))[12]);
那么,这里到底发生了什么?
state = new block[cost];
prev_block = state[foo];
类似于:
int* arr = new int[size];
int a = arr[index];
这是基本的 C++。我不确定为什么会造成混淆。
您混淆了此处涉及的两个 operator[]
。在上一个示例中,您设置了 state[0][12] = 12
,并将其与 state[12][12]
进行了比较。由于 state
是 block*
,state[n]
只是正常的数组访问;它不会调用 block
中定义的 operator[]
。
这里有很多概念混淆。我将对我看到的所有问题进行全面介绍,因为它们都很重要,而不仅仅是直接的答案。
state
是指向块的指针,但 state[0]
应该只是一个块,特别是状态中的第一个块,也是 *state
的结果。
prev_block = state[foo];
block中的所有数据都很简单,就是一个独立的字节数组,所以应该可以直接复制,不需要任何特殊的帮助。 prev_block = state[foo]
应该将状态 [foo] 复制到 prev_block。因为是副本,地址会不一样
在提供的打印输出代码中:
state->v[8*12] = 12;
为清楚起见,将他分解。 state->
将访问状态数组的第一个元素。 state->v[8*12]
将访问 state[0] 的 v[8*12]。 state->v[8*12] = 12;
会将 state[0] 的 v[8*12] 设置为 12。这意味着 v 的字节 96 将为 12。要引用不同的状态,您可以使用 (state + array_index)->v[8*12];
或 state[array_index].v[8*12];
我发现后者更具可读性。
printf("%" PRIu64 "\n", (*state)[12]);
(*state)
为您提供数组中的第一个状态,即 state[0]
。 (*state)[12]
使用 state[0]
的 [] 运算符,定义为 uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
这将 return 一个 64 位整数,从 state[0].v[12*8] 的地址开始,由数组 v 的下一个 8 个字节组成(v[96] 到v[103],结果为 12,0,0,0,0,0,0,0)。这将是 12 或一个非常大的数字,具体取决于系统的 endian。包装 printf 将打印 returned 数字。
prev_block = state[12];
将把状态数组的第 13 个元素复制到 prev_block,假设 state = new block[cost];
创建了足够多的块。没什么神奇的,但除了零之外不应该有任何东西,因为唯一设置了任何值的状态是 state[0]。您要么想在此处复制 state[0]
,要么写到 state[12]
上几行。
printf("%" PRIu64 "\n", (*(&prev_block))[12]);
* 和 & 在完成任何事情之前相互抵消。然后它将打印出使用 block [] 运算符的结果,如上。应该为零。