【发布时间】: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-> node : 0x603060,DataA结构地址为DataA ndata : 0x603010。减去0x603060 - 0x603010 = 80 bytes。更不用说这是从列表中取回数据的唯一方法。看showlistAin this source添加的printf语句