C中纠结的句法位

时间:2014-07-17 06:53:21

标签: c pointers syntax

我很难理解这一点,它将字符串写入结构的字段:

struct_t* P = (struсt_t*)malloc(sizeof(struct_t))
size_t offset = offsetof(struct, field);
char **strfield = (char **)(((char *)P) + offset);//the bit I don't fully understand
gets (string); 
*strfield = malloc (strlen (string) + 1);
strcpy (*strfield, string);

如何正确缠绕?我的意思是括号和星号。

P.S。这是程序的一部分,其中offset值定义函数的行为,具体取决于调用它的偏移值的参数。也就是说,它要么填写P->性别,要么填充P->。

3 个答案:

答案 0 :(得分:2)

编辑:写完这个答案后,问题已经有所澄清,可能会使答案不太合适。但是,我保留其余内容不变,因为仍然不清楚OP的实际代码是什么样的。

看起来编写此代码的人需要在结构的同一字段中存储不同的类型。为什么你只是为了访问结构成员而跳过这样的箍?看到struct_t的定义会很有启发性,但让我们说它看起来像这样:

糟糕的方式

struct struct_t {
  T1  f1;
  T2  f2;
  int field;
};

为了在不同时间将field成员用于不同类型的数据,您需要通过适当类型的指针访问它。

首先我们需要field成员的地址:

size_t offset = offsetof(struct, field);

offsetof运算符从结构的第一个字节为您提供结构成员的偏移量。然后,您需要计算指向此地址的指针,并将其强制转换为适当的类型。

首先是指向结构的第一个字节的指针,然后将其强制转换为字符类型:

char **strfield = (char **)(((char *)P) + offset);

然后添加偏移量:

char **strfield = (char **)(((char *)P) + offset);

如果要在char *中存储指向char(field)的指针,则指向 field指针必须是指针指向char(char **)的指针:

char **strfield = (char **)(((char *)P) + offset);

现在我们要在field中存储内容,但使用strfield来存储我们想要的实际数据类型:

*strfield = malloc (strlen (string) + 1);
strcpy (*strfield, string);

*strfield取消引用指向field的指针,从malloc()返回的指针存储在结构内field成员的位置,并将字符串复制到分配的内存。

为什么这很糟糕

这很糟糕,因为field成员未必为您要存储的类型正确对齐。这会导致未定义的行为,这可能导致程序崩溃,运行缓慢,提供不正确的结果或完全意外的事情。或者最糟糕的是,多年来一直运行良好直到为大客户做示范。

幸运的是,C有办法正确地做到这一点:

好方法

正确且更简单的方法是使用union

struct struct_t {
  T1 f1;
  T2 f2;
  union {
    int intfield;
    char *strfield;
    int (*functionfield)(char *, ...);
  } field;
};

现在,您可以field成员P->field.strfield或任何其他类型访问{{1}}成员,并保证该字段已正确对齐联盟内的所有类型。

当然,只有在通过同一个union成员存储和检索值时,或者至少通过相同类型的指针,才会定义行为。

答案 1 :(得分:1)

您希望strfield指向field中的Pfield是结构中的char *成员,因此其指针strfieldchar **变量。

field位于P起始地址+ offset字节。

由于指针算术,如果你想要添加offset字节,你必须将P转换为char *,否则你将offset的大小增加struct_t倍结构。

答案 2 :(得分:1)

char **strfield = (char **)(((char *)P) + offset);//the bit I don't fully understand

是在结构中一般访问字段的另一种方法。 strfield,可推测的sting-field是指向指针的指针,该指针将用于保存指向结构中字符串字段的指针的地址。如果您有结构,则可以使用正常.->运算符访问其成员,并使用结构+ offset的名称。

上面的代码是创建一个指向地址P + offset的指针的指针,以便访问该地址的结构成员。例如,如果你有一个结构:

struct mystruct {
    int myint;
    char *mystr;
} mystruct;

您希望访问mystruct.mystr,您可以创建指向mystruct + offset的指针,其中偏移量等于sizeof (int)。因此,您将创建一个包含地址mystruct + sizeof (int)的指针(或指向指针的指针),以便访问该地址的mystr。这种访问方式通常用于利用空数据类型等的通用数据结构(链表等)。希望这会有所帮助。

另一个工具,offsetof命令可以帮助进行偏移计算。有关更深入的解释和良好示例,请参阅man offsetof