#define STRING(s) (((String*)s)-1)
世界上有什么(((String*)s)-1)
?
typedef
struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
答案 0 :(得分:8)
您正在将s
投射到String *
。然后你从中减去一个(使它指向以前的任何东西)。
任何更具体的东西都需要知道String
的定义 - 但是(WILD SPECULATION)我猜应用程序使用双VB / C风格的字符串(空终止,前面有长度),这个函数将它从适合C函数的形式(指向第一个字符的指针)更改为可用于另一个类型的指针(指向长度的指针)。
答案 1 :(得分:5)
在机械方面,宏可以像其他人已经描述的那样工作。但是,从语义上讲,您可以将其视为从char *
到String *
s的转换形式。
String
结构是计数字符串的标题,即您知道总长度而不必扫描NUL字节的字符串。此特定版本还保留已分配的总数。您可以按如下方式创建一个:
struct String *str = malloc(sizeof(*s) + maxlen);
str->length = 0;
str->capacity = maxlen;
str->checked = /* ??? */;
在某处应该有一些各种各样的功能来操纵这些计数的字符串。
宏本身就是一个普通的char *
,假设指向上面分配的String
的第一个字符,回到String *
。它会用到这样的东西:
/* allocate str as above */
char *s = str->p;
现在,通过一系列函数调用或返回,您以某种方式松散跟踪包含s
的String结构,并且您需要再次找到它。你写道:
String *str2 = STRING(s);
这不是在C中实现计数字符串的特别好方法,但它演示了一种人们不时看到的技术。
答案 2 :(得分:2)
其他人回答了你的问题。在ptr
内struct String
声明零大小的技术称为“the struct hack”和wasn't portable until C99(尽管它在C99之前被广泛使用,似乎无处不在) 。我们的想法是ptr
使用0个字节,所以如果你有一个指向ptr
的指针,并想要一个原始结构,你可以使用STRING
宏。您要从struct
成员的地址中减去ptr
的大小,从而获取struct
的起始地址。
在给定指向其任何成员的指针的情况下,获取struct
的起始地址的更好方法是使用offsetof()
中定义的stddef.h
宏。顾名思义,offsetof(struct type, member)
会在member
中给出struct type
的偏移:
#define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr))))
然后你可以这样做:
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
typedef struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
#define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr))))
int main(void)
{
String *s = malloc(sizeof *s + 100);
String *t;
char *mystring = s->ptr;
t = STRING(mystring);
assert(t == s);
return EXIT_SUCCESS;
}
offsetof()
在stddef.h
中定义。
请注意,在C99中,“struct hack”会在ptr
内声明struct
为:
char ptr[];
即,没有大小。
答案 3 :(得分:0)
不知道为什么用这种方式制作宏。可能String的定义需要这个,但这只是一个疯狂的猜测。