Of course I know about padding and alignment in structs.
My estimation for the size on a 64 bit Linux box was 128 byte. But sizeof() from gcc tells me 144, which is 16 bytes more. So I hacked this C code together:
So sizeof() gives 144, but offset of last field seems to be 120. Last field is a 8 byte pointer, so total size should be 128. And 128 is 8 * 16, so no reason for padding. It is strange. May the reason is that NiceCandidate is a Boxed type, so a hidden field? I don’t think so, from the header file it is just a struct. What is special is that it contains two fields of type NiceAddress which is a struct containing a union of size 28 bytes each.
So there are 3 more pointers, bringing you from 120 bytes to 144 bytes in your case.
Generally, getting the sizes of structs right from the .gir files is rather tricky though. Sometimes fields are parsed wrongly, sometimes there are bitfields that need to be handled correctly, and you have to handle padding/alignment correctly according to the C rules for your specific platform.
Without language support that’s a bit of work, I hope Nim has the ability to define structs according to the platform’s C ABI
You made me feel like a moron, my only excuse was that I was a bit tired yesterday. But look at
$ grep -A16 _NiceCandidate /home/salewski/libnice/agent/candidate.h
typedef struct _NiceCandidate NiceCandidate;
/**
* NiceCandidate:
* @type: The type of candidate
* @transport: The transport being used for the candidate
* @addr: The #NiceAddress of the candidate
* @base_addr: The #NiceAddress of the base address used by the candidate
* @priority: The priority of the candidate <emphasis> see note </emphasis>
* @stream_id: The ID of the stream to which belongs the candidate
* @component_id: The ID of the component to which belongs the candidate
* @foundation: The foundation of the candidate
* @username: The candidate-specific username to use (overrides the one set
* by nice_agent_set_local_credentials() or nice_agent_set_remote_credentials())
* @password: The candidate-specific password to use (overrides the one set
* by nice_agent_set_local_credentials() or nice_agent_set_remote_credentials())
--
struct _NiceCandidate
{
NiceCandidateType type;
NiceCandidateTransport transport;
NiceAddress addr;
NiceAddress base_addr;
guint32 priority;
guint stream_id;
guint component_id;
gchar foundation[NICE_CANDIDATE_MAX_FOUNDATION];
gchar *username; /* pointer to a nul-terminated username string */
gchar *password; /* pointer to a nul-terminated password string */
};
And that libnice I recently got directly from gitlab sources. So my gcc compiler seems to use a different header file? But OK, that should not be a real problem, I just tried to understand it.
The main problem about NiceCandidate struct for gobject-introspection is that there are no getters or setters for the fields defined, and NiceAdress is a struct which contains a union, but it is reported as a struct with no fields by gir. But we have to know size of NiceAdress (28 bytes) to access the fields below it.
Nim supports all that well, for NiceAdress we have already this solution
import nativesockets
type
# See https://gitlab.freedesktop.org/libnice/libnice/-/blob/master/agent/address.h
Address* {.union.} = object
`addr`*: SockAddr
ip4*: Sockaddr_in
ip6*: Sockaddr_in6
I think we do not really need the fields of NiceAgent, but we need its correct size.
That’s because it contains types that gir can’t handle (the union and the struct sockaddrs). You need to work around it manually on your side if you need to access those fields.
Ideally libnice would add GObject properties or accessor functions for the fields as field access is always a bit complicated for non-C-languages, as you found out here.