C: melhor maneira de fazer sizeof (((SomeStruct *) 0) -> some_member)?
Pergunta
Eu quero obter o tamanho de um membro específico em um struct.
sizeof(((SomeStruct *) 0)->some_member)
trabalha para mim, mas eu sinto que pode haver uma maneira mais agradável para fazê-lo.
Eu poderia #define SIZEOF_ELEM(STRUCT, ELEM) sizeof(((STRUCT *) 0)->ELEM)
e depois usar SIZEOF_ELEM(SomeStruct, some_member)
, mas gostaria de saber se já existe algo melhor built-in.
Meu caso de uso específico está em hsc2hs (emperramentos Haskell C).
pokeArray (plusPtr context (#offset AVFormatContext, filename)) .
take (#size ((AVFormatContext *) 0)->filename) .
(++ repeat '\NUL') $ filename
Solução
O que você tem é tão limpo quanto ele ganha, se você não pode garantir que você tem uma variável para excluir a referência. (Se você pode, em seguida, usar apenas sizeof(var.member)
ou sizeof(ptr->member)
, é claro, mas isso não vai funcionar em alguns contextos onde é necessária uma constante de tempo de compilação.)
Uma vez em cima de um longo, longo tempo atrás (circa 1990), eu corri para um compilador que tinha 'offsetof
' definido usando o endereço de base 0, e ele caiu. Eu trabalhei em torno do problema cortando <stddef.h>
a usar 1024 em vez de 0. Mas você não deve correr em tais problemas agora.
Outras dicas
Eu acredito que você já tem a solução correta lá. Você poderia desenterrar o seu stddef.h e procurar como offsetof é definida, uma vez que ele faz uma coisa muito similar.
Lembre-se que pode haver uma diferença entre o sizeof um membro e a diferença entre os offsetofs desse membro e o próximo, devido ao estofamento.
Em C ++ você poderia fazer sizeof (SomeStruct :: some_member), mas esta é c e você não tem operador de resolução de escopo. O que você escreveu é tão bom quanto pode ser escrito, tanto quanto eu sei.
Microsoft tem o seguinte em um de seus cabeçalhos:
#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
Eu não vejo nenhuma razão para fazer diferente.
Eles têm macros relacionados para:
RTL_SIZEOF_THROUGH_FIELD()
RTL_CONTAINS_FIELD()
eo bacana:
CONTAINING_RECORD()
que ajuda a implementar listas genéricas em linha reta C sem ter de exigir que os campos de link estar no início de um struct. Veja este Kernel Mustard artigo para mais detalhes.