简体   繁体   English

c结构通过偏移量获取数据

[英]c struct grabbing data by offset

Lets say I have this struct: 可以说我有这个结构:

typedef struct nKey {
    int num;
    widget* widget;
} NUMBER_KEY;

and a function: 和一个功能:

void dialKey(widget* widget) {
    // Need to print 'num' of the struct that this widget resides in
}

How do I go about accomplishing this? 我该如何完成这项工作? I tried something like: 我尝试了类似的东西:

    printf("%d", * (int *) widget - sizeof(int)); // Failure.org

edit: it is safe to assume that the widget being passed is in fact a member of a NUMBER_KEY struct 编辑:可以安全地假设所传递的小部件实际上是NUMBER_KEY结构的成员

edit: looking for a solution to the problem not another method. 编辑:寻找问题的解决方案而不是另一种方法。

As Michael explains in his answer, you cannot do it with given constraints because there's no way to "walk back" the pointer graph. 正如Michael在回答中解释的那样,您不能在给定的约束下完成此操作,因为无法“返回”指针图。 To make things more obvious, let me draw a diagram of objects (in C terms, not in OOP sense) involved: 为了使事情更明显,让我画一个涉及的对象图(用C术语表示,而不是OOP含义):

+- NUMBER_KEY --+
|  ...          | points to      
| widget field -+-----------+
|  ...          |           |
+---------------+           |   + widget +
                            +-->|  ...   |
                                |  ...   |
                            +-->|  ...   |
                            |   +--------+
                  points to |
[widget argument]-----------+

Notice the arrows. 注意箭头。 They are one-way - you can "walk" from a pointer to pointed value, but you cannot "walk" back. 它们是单向的-您可以从指针“移动”到指向的值,但是不能“移动”回去。 So you can deference widget argument of your function to get to the widget object, but once there, there's no way to tell who else points at it - including any instances of NUMBER_KEY structs. 因此,您可以引用函数的widget参数来获取widget对象,但是一旦到达该对象,就无法告诉其他人指向它了-包括NUMBER_KEY结构的任何实例。 Think about it: what if you had a dozen other pointers to the same widget , some of them from different NUMBER_KEY objects? 想一想:如果您有十二个指向同一widget其他指针,其中有一些来自不同的NUMBER_KEY对象,该怎么办? How could it possibly track that without keeping a list of all pointers within widget object? 如果不在widget对象中保留所有指针的列表,如何跟踪呢? If you actually need this, it's what you'll have to do - make widget point to its owning NUMBER_KEY . 如果您确实需要它,这就是您需要做的-使widget指向它自己的NUMBER_KEY

Given just a widgit* and not a widgit** being passed into dialKey, there's no way to do what you want (a widgit* value has no relationship to the NUMBER_KEY struct). 只给一个widgit *而不是一个widgit **传递给DialKey,就没有办法做你想要的事情(一个widgit *值与NUMBER_KEY结构没有关系)。 Assuming that you really mean something like: 假设您的意思确实是这样的:

void dialKey(widget** ppWidget) 
{    
    // Need to print 'num' of the struct that this widget resides in
}

Microsoft has a nifty macro for doing this type of thing (it helps with being able to have routines that manipulate linked lists genericly in C): 微软有一个漂亮的宏可以做这种事情(它有助于使例程能够以C语言通用地操作链表):

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                               (PCHAR)(address) - \
                               (ULONG_PTR)(&((type *)0)->field)))

You could use this like so: 您可以这样使用:

NUMBER_KEY* pNumberKey = CONTAINING_RECORD( *ppWidgit, NUMBER_KEY, widgit);

printf( "%d", pNumberKey->num);

The memory layout of a struct is defined by your compiler, your code would only work if you have 0 byte padding between struct members. 结构的内存布局是由编译器定义的,只有在结构成员之间填充0字节填充时,代码才能工作。 Usually this is not recommended b/c 0 byte padding would have your struct overlay across the standard read sizes of most processors. 通常不建议这样做,因为b / c 0字节填充会使结构覆盖大多数处理器的标准读取大小。

Some useful macros for your problem: 一些对您的问题有用的宏:

#define GET_FIELD_OFFSET(type, field)    ((LONG)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field)      (sizeof(((type *)0)->field))

example: 例:

NUMBER_KEY key;
key.num = 55;
int nOffSetWidget = GET_FIELD_OFFSET( NUMBER_KEY, widget);
int *pKeyNumAddress = (int *) &(key.widget) - nOffSetWidget );

printf("%d", * pKeyNumAddress );    // Should print '55'

C standard defines offsetof() macro (defined in stddef.h header), which is handy in your case. C标准定义了offsetof()宏(在stddef.h标头中定义),在您的情况下很方便。

#include <stddef.h>

void DialKey(widget** foo) {
    printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}

Note that you have to pass an address of struct field, not a value! 请注意,您必须传递一个struct字段的地址 ,而不是一个值!

The safest solution is to keep pointer to related nKey structure in widget 最安全的解决方案是在小部件中保留指向相关nKey结构的指针

 printf("%d", widget->myKey->num);

All other methods are unsafe 所有其他方法都不安全

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM