c struct 通过偏移量抓取数据

发布于 2024-07-30 07:29:08 字数 455 浏览 5 评论 0原文

假设我有这个结构:

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

和一个函数:

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

我该如何完成这个任务? 我尝试过类似的操作:

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

编辑:可以安全地假设正在传递的小部件实际上是 NUMBER_KEY 结构的成员

编辑:寻找问题的解决方案而不是其他方法。

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

edit: looking for a solution to the problem not another method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我最亲爱的 2024-08-06 07:29:08

正如迈克尔在他的回答中解释的那样,你不能在给定的约束下做到这一点,因为没有办法“走回”指针图。 为了让事情变得更明显,让我画一个所涉及的对象图(用 C 语言术语,而不是 OOP 意义上的):

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

注意箭头。 它们是单向的——您可以从指针“行走”到指向的值,但不能“行走”回来。 因此,您可以遵循函数的 widget 参数来获取 widget 对象,但是一旦到达,就无法知道还有谁指向它 - 包括 widget 的任何实例code>NUMBER_KEY 结构。 想一想:如果您有十几个指向同一个 widget 的其他指针,其中一些来自不同的 NUMBER_KEY 对象,该怎么办? 如果不保留 widget 对象中所有指针的列表,它怎么可能跟踪呢? 如果您确实需要这个,那么您必须这样做 - 让 widget 指向其所属的 NUMBER_KEY

As Michael explains in his answer, you cannot do it with given constraints because there's no way to "walk back" the pointer graph. To make things more obvious, let me draw a diagram of objects (in C terms, not in OOP sense) involved:

+- 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. Think about it: what if you had a dozen other pointers to the same widget, some of them from different NUMBER_KEY objects? How could it possibly track that without keeping a list of all pointers within widget object? If you actually need this, it's what you'll have to do - make widget point to its owning NUMBER_KEY.

少女情怀诗 2024-08-06 07:29:08

如果只将 widgit* 而不是 widgit** 传递给 dialKey,则无法执行您想要的操作(widgit* 值与 NUMBER_KEY 结构没有关系)。 假设你的意思确实是这样的:

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

微软有一个漂亮的宏来做这种类型的事情(它有助于能够拥有在 C 中一般操作链接列表的例程):

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

你可以像这样使用它:

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

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

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). 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):

#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);
九局 2024-08-06 07:29:08

结构体的内存布局由编译器定义,只有在结构体成员之间有 0 字节填充时,您的代码才能工作。 通常不建议这样做,因为 0 字节填充会使您的结构覆盖大多数处理器的标准读取大小。

针对您的问题的一些有用的宏:

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

示例:

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'

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. Usually this is not recommended b/c 0 byte padding would have your struct overlay across the standard read sizes of most processors.

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'
满身野味 2024-08-06 07:29:08

最安全的解决方案是在 widget 中保留指向相关 nKey 结构的指针

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

所有其他方法都是不安全的

The safest solution is to keep pointer to related nKey structure in widget

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

All other methods are unsafe

北音执念 2024-08-06 07:29:08

C 标准定义了 offsetof() 宏(在 stddef.h 标头中定义),这在您的情况下很方便。

#include <stddef.h>

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

请注意,您必须传递结构字段的地址,而不是值!

C standard defines offsetof() macro (defined in stddef.h header), which is handy in your case.

#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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文