使用struct的C指针算术

时间:2017-02-15 21:45:58

标签: c string pointers struct

我目前正在C中编写一个新的String结构,如下所示,并练习指针运算。

struct String {
    uint32_t check;
    uint32_t capacity;
    uint32_t length;
    char data[1];

} String;

我对这部分代码感到有点困惑

define STRING(s) ((String*)(s - 3*sizeof(uint32_t)))

void utstrfree(char* self) {

//    if(*(self - sizeof(uint32_t) * 3) == SIGNATURE) WHY DOES THIS NOT >WORK?

    assert((STRING(self)->check) == SIGNATURE);     //check if it's a >utstring

    free(self-sizeof(uint32_t) * 3);    //properly free the malloc and alternative could have been free(STRING(self))

}

我理解我的STRING宏如何工作并且它正常工作但我不太清楚为什么我的if语句不起作用。任何人都可以向我解释这个吗?

2 个答案:

答案 0 :(得分:2)

正如@AslakBerby已经观察到的那样,断言中的表达式(我假设 )起作用,并不等同于已注释掉的if语句中的条件表达式。特别是,由于selfchar *,因此表达式*(self - sizeof(uint32_t) * 3)的类型为char,而表达式STRING(self)->check的类型为uint32_t。假设对后者进行评估已经定义了行为,前者仅在系统特定的存储顺序中产生后者的第一个字节。

总的来说,尽管这个一般方案起作用,但它很脆弱且不安全:

  • 它假设类型struct String的表示不需要实现;
  • 它通常会超出数组边界,从而调用未定义的行为;
  • 它没有提供表示就地子串的机制;
  • 它提供了与标准库的字符串函数的充分互操作,使用户期望获得比实际提供的更大的互操作性。

建议:

  • 依靠offsetof()计算结构中的相对位置。它既安全又清晰。
  • 甚至不尝试与普通char数组字符串直接互操作 - 将这些对象处理为实际的对象。毕竟,这种练习的重点通常不是数据结构本身,而是与之相关的改进功能,例如strlen()的O(1)版本。没有必要尽量使用标准库的功能来使用这些对象。
  • 考虑使用指向数据的指针,而不是直接在对象中嵌入数据。这肯定会更好地适应调整大小,它也可以支持就地子串。
  • 如果您直接在对象中嵌入数据,则使用灵活的阵列成员来执行此操作。

答案 1 :(得分:1)

好吧,你的if不等于宏。如果你应该输入它,它应该是这样的:

if(((String*)(self - 3*sizeof(uint32_t)))->check) == SIGNATURE) ...

您需要对您创建的指针进行类型转换,然后使用您要查找的属性。