我试图在这种情况下理解指针转换。
# https://github.com/udp/json-parser/blob/master/json.c#L408
#define json_char char
typedef struct _json_object_entry
{
json_char * name;
unsigned int name_length;
struct _json_value * value;
} json_object_entry;
typedef struct _json_value
{
struct
{
unsigned int length;
json_object_entry * values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} object;
}
(*(json_char **) &top->u.object.values) += string_length + 1;
由于我看到top->u.object.values
具有值的第一个元素的地址(类型:json_object_entry),然后我们获取值的地址,将其转换为char,..从这里我&#39我输了。我真的不明白这个目的。
//注意:对于那些想知道这是什么的人来说,这是两个传递解析器。
由于
答案 0 :(得分:2)
_json_value::values
是一个指向json_object_entry
数组开头(或进入)的指针。代码将其值调整几个字节,例如为了在实际数据之前跳过标题等。由于指针是键入的,因此只能在sizeof(_json_object_entry)
的常量中更改其值,但显然偏移量可以具有任何值,具体取决于某些string_length
。所以指针的地址被占用,转换为char指针的地址(char指针可以以1为增量进行更改),取消引用,因此结果是一个指向char的指针,它位于与真实{{1}相同的位置},然后分配给。
如果架构要求结构的最小对齐(可能取决于它们的第一个元素,这里是指针),并且字符串长度可以具有不是该值的倍数的值,那么应该添加这样的代码可能在运行时中断。对准。这将使代码UB。如果保留对齐,我不确定代码是否名义上是UB。
答案 1 :(得分:1)
此处作者(有罪......)
在第一次传递中,values
尚未分配,因此解析器通过使用相同的字段来存储当前需要的内存量(长度)时作弊。它实际上是在第二次传递中分配的。
if (state.first_pass)
(*(json_char **) &top->u.object.values) += string_length + 1;
对json_char
进行投射,以便我们将char
的倍数添加到长度,而不是json_object_entry
的倍数。
有点(......好吧,不止一点......)肮脏的黑客重新使用这样的字段,但它是为了保存向json_value
添加另一个字段或使用联盟(C89联盟不能匿名,所以它会使json_value
的结构有点怪异。)
这里没有UB,因为我们此时并未实际使用values
作为结构数组,只是颠覆类型系统并将其用作整数。
答案 2 :(得分:0)
json_object_entry * values;
...
}
(*(json_char **) &top->u.object.values) += string_length + 1;
忘记类型的正确性,你可以崩溃&和*:
((json_char **) top->u.object.values) += string_length + 1;
top-> u.object.values确实是指向values数组的第一个元素的指针。它指向指向json_char的指针,然后是高级string_length + 1个字符。最终结果是top-> u.object.values现在指向(string_length + 1)json_chars,比以前更早。