【问题标题】:c linked-list, offsetof returns value that does not allow cast back to parent struct addressc链表,offsetof返回不允许转换回父结构地址的值
【发布时间】:2014-04-10 03:48:44
【问题描述】:

相关文章: [c 循环双链表:rev traverse 为同一节点提供不同的列表指针地址] (c circular double linked-list: rev traverse gives different list-pointer address for same node)

使用嵌入在数据结构中的通用列表结构实现循环双链表[上述相关帖子中的解决方案(3)] 我遇到了offsetof(struct,member) 返回不正确的问题抵消。这会阻止使用该解决方案。我知道报告的偏移量可能取决于编译器,但我需要知道如何处理编译器给出的任何结果。 full source is this link。下面显示了列表实现和接收到的不正确的 offsetof 值。我不知道为什么返回的 offsefof 值不是实际需要的。例如,在下面的代码中,offsetof (DataA,node) 将偏移量(unsigned long)报告为 24,但是需要 80 的值?

typedef struct Node {
struct Node *prev, *next;
} Node;

typedef struct DataA {
int i;
char c;
double d;
char *a;
Node *node;
} DataA;

void
showlistA (Node *list, int manoff)
{
if (list ==  NULL) {
    fprintf (stdout,"%s(), The list is empty\n",__func__);
    return;
}

Node *iter = list;

do {
    int offset = (int)offsetof (DataA, node);
    DataA *offsetaddr = (DataA*)((unsigned long)iter - (unsigned long)offset);
    printf ("node: %p,  offsetof(DataA,node): %d,       result: %p,\n\t\t\t  \
            need offset: %d,  need result: %p\n\n",
        iter, offset, offsetaddr, manoff, (DataA*)((unsigned long)iter - manoff));

    iter = iter-> next;
} while (iter != list);
}

int
main(int argc, char *argv[])
{

Node *list = NULL;
int manoffset = 80;

if (argc < 2)
    fprintf(stderr, "\nNote:  Usage: %s (int) (offsetof(DataA,node)) (default: 80)\n", argv[0]);

manoffset = (argv[1]) ? atoi (argv[1]) : 80;

printf ("\ncreate_node_Ann()\n");
create_node_Ann (&list, 1, 'A', 1000.101, "my dog has fleas");
create_node_Ann (&list, 2, 'B', 2000.101, "my cat has more");
create_node_Ann (&list, 3, 'C', 3000.101, "my snake has none");
create_node_Ann (&list, 4, 'D', 4000.101, "my hamster is fine");

printf ("\nNumber of nodes in 'list': %d\n\n", get_list_sz (list));

printf ("Node pointers (list validation):\n");
showlistptrs (list);
printf ("\n");
printf ("Offsets (reported/required):\n");
showlistA (list, manoffset);

/* Output is compiler dependent - reported results */
printf ("Offsets reported for each member of DataA:\n");
printf ("    offsets: i=%ld; c=%ld; d=%ld; a=%ld; node=%ld\n",
    (long) offsetof(struct DataA, i),
    (long) offsetof(struct DataA, c),
    (long) offsetof(struct DataA, d),
    (long) offsetof(struct DataA, a),
    (long) offsetof(struct DataA, node));
printf ("    sizeof(struct DataA)=%ld\n\n", (long) sizeof(struct DataA));

exit(EXIT_SUCCESS);
}

显示与列表信息一起返回的值的偏移量的输出是:

create_node_Ann()
1  DataA ndata  : 0x603010
   ndata-> node : 0x603060
2  DataA ndata  : 0x603080
   ndata-> node : 0x6030d0
3  DataA ndata  : 0x6030f0
   ndata-> node : 0x603140
4  DataA ndata  : 0x603160
   ndata-> node : 0x6031b0

Number of nodes in 'list': 4

Node pointers (list validation)
1  prev: 0x6031b0  cur: 0x603060  next: 0x6030d0
2  prev: 0x603060  cur: 0x6030d0  next: 0x603140
3  prev: 0x6030d0  cur: 0x603140  next: 0x6031b0
4  prev: 0x603140  cur: 0x6031b0  next: 0x603060

Offsets (reported/required):
node: 0x603060,  offsetof(DataA,node): 24,       result: 0x603048,
                          need offset: 80,  need result: 0x603010

node: 0x6030d0,  offsetof(DataA,node): 24,       result: 0x6030b8,
                          need offset: 80,  need result: 0x603080

node: 0x603140,  offsetof(DataA,node): 24,       result: 0x603128,
                          need offset: 80,  need result: 0x6030f0

node: 0x6031b0,  offsetof(DataA,node): 24,       result: 0x603198,
                          need offset: 80,  need result: 0x603160

Offsets reported for each member of DataA:
offsets: i=0; c=4; d=8; a=16; node=24
sizeof(struct DataA)=32

我不明白为什么 offsetof 值与所需的值如此不同。为什么DataA *p = (DataA*)((uintptr_t)iter - offsetof(DataA, node)); 返回24 而不是80?完整程序采用单个参数(偏移量)并将其作为手动偏移量应用,以允许在列表节点和要输入的 DataA 结构地址之间进行正确转换。 (这就是我测试实际需要的东西的方式,以及我的计算器)。我该如何解决这个问题?

【问题讨论】:

  • 你这样做有什么原因吗?看起来很尴尬。
  • 4+4+8+4+4 = 24 。为什么你会认为它是 80?
  • 我找不到“解决方案 3”,但大多数情况下,当您实现“侵入式”链表时,您会在数据中存储一个结构,而不是指针。
  • @Jim:我认为是 4 + 4 + 8 + 8,因为它是 offsetof(node),而不是 sizeof(DataA)。但这都是猜测,不是吗?
  • 为什么是 80?看节点1:嵌入列表地址为ndata-&gt; node : 0x603060,DataA结构地址为DataA ndata : 0x603010。减去0x603060 - 0x603010 = 80 bytes。更不用说这是从列表中取回数据的唯一方法。看showlistAin this source添加的printf语句

标签: c list struct


【解决方案1】:

问题出在 DataA 的定义中,其中节点定义为指针,而不是 @molbdnilo 指出的结构。 struct DataA的正确定义是:

typedef struct DataA {
    int i;
    char c;
    double d;
    char *a;
    Node node;
} DataA;

将 node 重新定义为结构而不是指向结构的指针后,offsetof 值是正确的。感谢大家的帮助。

【讨论】:

    猜你喜欢
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 2020-04-10
    • 2013-08-23
    • 2021-02-03
    • 1970-01-01
    相关资源
    最近更新 更多