丑陋的宏观解释(仅1行)

时间:2010-01-10 22:29:52

标签: c

#define STRING(s) (((String*)s)-1)

世界上有什么(((String*)s)-1)

typedef 
struct String {
    int length;
    int capacity;
    unsigned check;
    char ptr[0];
} String;

4 个答案:

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

其他人回答了你的问题。在ptrstruct 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 *)=类型强制转换为String对象的指针,
  • s =字符串,
  • -1 =指向一个String对象在内存块之前的长度

不知道为什么用这种方式制作宏。可能String的定义需要这个,但这只是一个疯狂的猜测。