【问题标题】:Typecasting structure pointers类型转换结构指针
【发布时间】:2016-05-05 18:38:59
【问题描述】:

大家好。我正在使用名为Pointers in C: A Hands on Approach 的书研究结构和指针,在第 107 页,我遇到了一个不完整的结构类型转换示例。我试图通过实现函数 receivedata() 、添加标题并进行一些更改来使其工作。
这是完整的代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct signature
{
    char  sign;
    char version;
};

struct id
{
    char id;
    char platform;
};

struct data
{
    struct id idv;
    struct signature sig;
    char data[100];
};

static void receivedata(struct data *d);
static struct signature *extractsignature(struct data *d);
static struct id *extractid(struct data *d);

int main(int argc, char *argv[])
{
/* Actual line in book is :
*  struct data *img; with no memory allocation or assignment to NULL.
*  Had errors so i allocated memory on the heap before passing the value to 
*  Receivedata(); */
    struct data *img = malloc(sizeof(struct data));

    receivedata(img);

/* Actual line in book is :
 *   struct id *idval = extractid(&img);
 *   struct signature *sig = extractsignature(&img);
 * This is obviously erroneous because &img is a pointer 
 * to a pointer (struct data**) which is not the data type for 
 * the extract functions' argument */
    struct id *idval = extractid(img);
    struct signature *sig = extractsignature(img);

    printf("For signature:\n");
    printf("sign = %c", sig->sign);
    printf(" version = %c\n\n", sig->version);

    printf("For id:\n");
    printf("id = %c", idval->id);
    printf(" platform = %c", idval->platform);

    printf("\ndata = %s", img->data);

    return 0;
}

static struct signature *extractsignature(struct data *d)
{
    struct signature *sig = (struct signature *)d;
    return sig;
}

static struct id *extractid(struct data *d)
{
    struct id *idv = (struct id *)d;
    return idv;
}

static void receivedata(struct data *d)
{
    struct data *dptr = d;
    char *ch = "CODING IS COOL!";

    dptr->sig.sign = 's';
    dptr->sig.version = '1';

    dptr->idv.id = 'i';
    dptr->idv.platform = 'p';

    strncpy(dptr->data, ch, strlen(ch));

    return;
}

我想了解的是函数 extractid() 和 extraxtsignature() 内部的转换,因为看起来我们正在转换 struct data * 以便检索其各个成员。我运行了这个程序,我得到的是struct data 的第一个成员对于 sig 成员和 id 成员的值。这是struct id 在struct data 中排在第一位时的输出:

For signature:
sign = i version = p

For id:
id = i platform = p
data = CODING IS COOL!

当struct signature 是第一个元素时:

For signature:
sign = s version = 1

For id:
id = s platform = 1
data = CODING IS COOL!

最后,当char data[100] 是第一个元素时:

For signature:
sign = C version = O

For id:
id = C platform = O
data = CODING IS COOL!

请您解释一下这种类型的投射、何时使用它以及最佳做法。非常感谢。

【问题讨论】:

    标签: c pointers struct


    【解决方案1】:
    struct data
    {
        struct id idv;
        struct signature sig;
        char data[100];
    };
    

    对于上面的定义,下面的extractid函数是有效的,会得到正确的结果。

    static struct id *extractid(struct data *d)
    {
        struct id *idv = (struct id *)d;
        return idv;
    }
    

    这是因为,struct id 是struct data 的第一个成员。所以,当你有struct data *d时,d指向struct data的起始地址,与第一个成员struct id的起始地址相同。

    因此,如果您正在转换结构的第一个成员,那么根据您上面提供的代码,它是正确的。

    【讨论】:

    • 感谢@Sri.U。所以你是说它对第二个成员不起作用?即extractsignature() 对上述定义无效
    • 是的,因为 d 指向 id。由于 signature 和 id 具有相同类型的成员(即 2 个 char 成员),在这种情况下,它会分别打印 id 和 platform 的值用于 sign 和 version。
    • 您的指针需要移动到正确的偏移量/地址,以便它指向签名的确切位置,才能按预期工作。
    • 谢谢。我现在几乎明白了,但你什么时候使用它,为什么不这样做:`struct id *idv = &d->idv; `?它有点解决问题。
    • 另外,如果你想对 extractsignature 做类似的事情,你可以在 extractsignature 函数中做类似的事情。使用 offset = offsetof(struct data, sig) 获取成员sig 的偏移量: 然后做struct signature *sig = (struct signature *)((char *)d + offset) ;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多