带结构的C指针算法

带结构的C指针算法,c,string,pointers,struct,C,String,Pointers,Struct,我目前正在用C编写一个新的字符串结构,如下所示,并练习指针算法 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(*(s

我目前正在用C编写一个新的字符串结构,如下所示,并练习指针算法

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))

}

我理解我的字符串宏是如何工作的,它工作正常,但我不太清楚为什么我的if语句不工作。有人能给我解释一下吗?

嗯,你的if不等于宏。如果你要打印出来,应该是这样的:

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

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

正如@AslakBerby已经观察到的那样,您的断言中的表达式(我假设该表达式有效)并不等同于您注释掉的if语句中的条件表达式。特别是,由于self是char*,表达式*self-sizeofuint32\u t*3的类型为char,而表达式STRINGself->check的类型为uint32\u t。假设对后者的评估已经定义了行为,则前者只生成后者的第一个字节,按照系统特定的存储顺序

但是,总的来说,就这个通用方案的有效性而言,它是脆弱和不安全的:

它对实现不需要满足的类型struct String的表示进行了假设; 它通常会超出数组边界,从而调用未定义的行为; 它不提供表示在位子字符串的机制; 它与标准库的字符串函数提供了足够的互操作性,使用户期望获得比实际提供的更高的互操作性。 建议:

依赖offsetof计算结构内的相对位置。它既安全又清晰。 甚至不要尝试直接与纯字符数组字符串进行互操作-按实际情况处理这些对象。毕竟,这类练习的重点通常不是数据结构本身,而是与之配套的改进功能,比如strlen的O1版本。无需特意将这些对象与标准库的函数配合使用。 考虑使用指向数据的指针,而不是直接在对象中嵌入数据。这无疑会更好地适应调整大小,并且它也可以支持就地子字符串。 如果确实将数据直接嵌入到对象中,则使用灵活的数组成员进行嵌入。
@user4581301现代C应该使用灵活的数组成员-char data[];,非字符数据[1];,否则,通过char*将大小的字符串操纵到灵活数组成员是合法的,尽管这有点可疑-不是很安全的类型。不,@user4581301,在以前的任何标准下都不符合犹太标准,尽管事实上它通常是有效的。如今,该标准通过直接支持这类事情。不要胡乱处理混乱的指针操作。您从malloc获得一个指针,并将完全相同的指针传递给free。不要冒任何其他危险。尽管尝试创建可变大小的结构是另一个问题……但最好用offsetofString、data替换3*sizeofuint32_t。@PSkocik:固定长度的数组与FAM不同,编译器可以预期数组不会超出其边界进行访问。IOW:访问固定宽度数组或超出其边界的VLA会调用未定义的行为。对于FAM,编译器知道它不知道边界,因此这里的访问是安全的。特别是,假设self是char*,if语句将char与签名进行比较。那似乎不是他想要的。是的。因为我们不知道签名是如何定义的,所以不可能说为什么不。然而,他可以这样做:如果*unit32_t*self-3*sizeofuint32_t==签名也应该起作用。