C:做sizeof的更好方法(((SomeStruct *)0) - > some_member)?

时间:2022-07-14 17:01:45

I want to get the size of a specific member in a struct.

我想获得结构中特定成员的大小。

sizeof(((SomeStruct *) 0)->some_member) works for me but I feel like there might be a nicer way to do it.

sizeof(((SomeStruct *)0) - > some_member)适合我,但我觉得可能有更好的方法来做到这一点。

I could #define SIZEOF_ELEM(STRUCT, ELEM) sizeof(((STRUCT *) 0)->ELEM) and then use SIZEOF_ELEM(SomeStruct, some_member), but I wonder whether there is already something better built-in.

我可以#define SIZEOF_ELEM(STRUCT,ELEM)sizeof(((STRUCT *)0) - > ELEM)然后使用SIZEOF_ELEM(SomeStruct,some_member),但我想知道是否已经有更好的内置功能。

My specific use-case is in hsc2hs (Haskell C bindings).

我的具体用例是hsc2hs(Haskell C绑定)。

pokeArray (plusPtr context (#offset AVFormatContext, filename)) .
  take (#size ((AVFormatContext *) 0)->filename) .
  (++ repeat '\NUL') $ filename

4 个解决方案

#1


What you've got is about as clean as it gets if you can't guarantee you have a variable to dereference. (If you can, then use just sizeof(var.member) or sizeof(ptr->member), of course, but this won't work in some contexts where a compile-time constant is needed.)

如果你不能保证你有一个变量来解除引用,那么你得到的就是干净利落。 (如果可以,那么当然只使用sizeof(var.member)或sizeof(ptr-> member),但这在需要编译时常量的某些上下文中不起作用。)

Once upon a long, long time ago (circa 1990), I ran into a compiler that had 'offsetof' defined using the base address 0, and it crashed. I worked around the problem by hacking <stddef.h> to use 1024 instead of 0. But you should not run into such problems now.

很久很久以前(大约1990年),我遇到了一个使用基址0定义'offsetof'的编译器,它崩溃了。我通过黑客攻击 来使用1024而不是0来解决这个问题。但是你现在不应该遇到这样的问题。

#2


I believe you've already got the correct solution there. You could dig up your stddef.h and look for how offsetof is defined, since it does a very similar thing.

我相信你已经有了正确的解决方案。您可以挖掘stddef.h并查找offsetof的定义方式,因为它的确非常类似。

Remember that there may well be a difference between the sizeof a member and the difference between the offsetofs of that member and the next one, due to padding.

请记住,由于填充,成员的大小与该成员的offsetofs与下一个成员的offsetof之间可能存在差异。

#3


In C++ you could do sizeof(SomeStruct::some_member), but this is c and you have no scope resolution operator. What you've written is as good as can be written, as far as I know.

在C ++中你可以做sizeof(SomeStruct :: some_member),但这是c并且你没有范围解析运算符。据我所知,你写的内容和写的一样好。

#4


Microsoft has the following in one of their headers:

Microsoft在其中一个标题中包含以下内容:

#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))

I see no reason to do any different.

我认为没有理由做任何不同的事情。

They have related macros for:

他们有相关的宏:

RTL_SIZEOF_THROUGH_FIELD()
RTL_CONTAINS_FIELD()

and the nifty:

和漂亮的:

CONTAINING_RECORD() 

which helps implement generic lists in straight C without having to require that link fields be at the start of a struct. See this Kernel Mustard article for details.

这有助于在直接C中实现通用列表,而不必要求链接字段位于结构的开头。有关详细信息,请参阅此内核Mustard文章。

#1


What you've got is about as clean as it gets if you can't guarantee you have a variable to dereference. (If you can, then use just sizeof(var.member) or sizeof(ptr->member), of course, but this won't work in some contexts where a compile-time constant is needed.)

如果你不能保证你有一个变量来解除引用,那么你得到的就是干净利落。 (如果可以,那么当然只使用sizeof(var.member)或sizeof(ptr-> member),但这在需要编译时常量的某些上下文中不起作用。)

Once upon a long, long time ago (circa 1990), I ran into a compiler that had 'offsetof' defined using the base address 0, and it crashed. I worked around the problem by hacking <stddef.h> to use 1024 instead of 0. But you should not run into such problems now.

很久很久以前(大约1990年),我遇到了一个使用基址0定义'offsetof'的编译器,它崩溃了。我通过黑客攻击 来使用1024而不是0来解决这个问题。但是你现在不应该遇到这样的问题。

#2


I believe you've already got the correct solution there. You could dig up your stddef.h and look for how offsetof is defined, since it does a very similar thing.

我相信你已经有了正确的解决方案。您可以挖掘stddef.h并查找offsetof的定义方式,因为它的确非常类似。

Remember that there may well be a difference between the sizeof a member and the difference between the offsetofs of that member and the next one, due to padding.

请记住,由于填充,成员的大小与该成员的offsetofs与下一个成员的offsetof之间可能存在差异。

#3


In C++ you could do sizeof(SomeStruct::some_member), but this is c and you have no scope resolution operator. What you've written is as good as can be written, as far as I know.

在C ++中你可以做sizeof(SomeStruct :: some_member),但这是c并且你没有范围解析运算符。据我所知,你写的内容和写的一样好。

#4


Microsoft has the following in one of their headers:

Microsoft在其中一个标题中包含以下内容:

#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))

I see no reason to do any different.

我认为没有理由做任何不同的事情。

They have related macros for:

他们有相关的宏:

RTL_SIZEOF_THROUGH_FIELD()
RTL_CONTAINS_FIELD()

and the nifty:

和漂亮的:

CONTAINING_RECORD() 

which helps implement generic lists in straight C without having to require that link fields be at the start of a struct. See this Kernel Mustard article for details.

这有助于在直接C中实现通用列表,而不必要求链接字段位于结构的开头。有关详细信息,请参阅此内核Mustard文章。