karlgoethebier has asked for the wisdom of the Perl Monks concerning the following question:

#include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 1 typedef struct _acme { int data; } * acme; int main(void) { acme gizmo[N]; gizmo[0] = (acme)malloc(sizeof(struct _acme)); size_t msize = malloc_usable_size(gizmo[0]); printf("malloc_usable_size(gizmo[0]) %lu\n", msize); free(gizmo[0]); return (1); }

This always allocates 24 bytes - whatever i pass to malloc. I’m a bit confused. What do i miss? Thanks in advance for enlightenment.

Update: Thanks to all for the kind and helpful replies.

Replies are listed 'Best First'.
Re: OT: Why does malloc always give me 24?
by cavac (Prior) on Aug 18, 2024 at 12:20 UTC

    What's the size of "int" on your system? It's nearly always best to use types with defined sizes, like int32_t.

    Also, i can' exactly make sense of what you are trying to do here. You are only allocating a single element. My "memory managment in C" is quite rusty, but if you want an array with N elements of type acme, i think it should be more in the line of this:

    #define N 10 typedef struct _acme { int data; } acme; acme *gizmo; gizmo* = (acme*)malloc(sizeof(acme) * N);

    But as i said, it's been a long time and i wrote this from memory.

    PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
    Also check out my sisters artwork and my weekly webcomics
      The answer to "why 24" will be that allocating a single byte, or 4, probably doesn't make sense with the amount of bookkeeping data involved. That malloc implementation is probably just making the minimum size be 24, quite possibly for alignment reasons.

      C99 has variable-length arrays (VLAs), which would allow this, where gizmo would be on the stack and evaporate on do_something's return:

      void do_something(int n) { struct acme gizmo[n]; int i; for (i=0; i<n; i++) { /* do stuff */ } }

      The code above has a syntax error: gizmo* = (acme*)malloc(sizeof(acme) * N) has an unnecessary "*" after "gizmo".

Re: OT: Why does malloc always give me 24?
by ikegami (Patriarch) on Aug 18, 2024 at 18:45 UTC

    You asked to allocate enough bytes for a struct _acme. As the struct _acme struct shouldn't have any padding, this should be the size of an int.

    An int must be at least 16 bits in size. On a desktop system, I expect it to be 32 bits, and I expect CHAR_BIT to be 8. On such a system, you asked to allocate 4 bytes.

    According to what you're saying, malloc allocated more than you requested. That's entirely reasonable, especially if the size returned includes the internal headers. It's also possible there's a minimum size the system can allocate.

    Whatever the reason, you may not use any of the memory beyond what you requested.

    From man7's page on malloc_usable_size():

    The value returned by malloc_usable_size() may be greater than the requested size of the allocation because of various internal implementation details, none of which the programmer should rely on. This function is intended to only be used for diagnostics and statistics; writing to the excess memory without first calling realloc(3) to resize the allocation is not supported. The returned value is only valid at the time of the call.

      Yes, thank you. I just read the manpage.

      For completeness:

      int 4 int32_t 4 _acme 4 gizmo 16 gizmo[0]->data 4 gizmo[1]->data 4 &gizmo[0] 0x7ffcf0263680 &gizmo[1] 0x7ffcf0263688 &gizmo[0]->data 0x55d34e8cf6b0 &gizmo[1]->data 0x55d34e8cf6d0 malloc_usable_size(gizmo[0]) 24 malloc_usable_size(gizmo[1]) 24

      ”…there's a minimum size the system can allocate”

      Secrecy? From ibidem: ”Secrets are sometimes kept to provide the pleasure of surprise.”

      Best regards, Karl

Re: OT: Why does malloc always give me 24?
by ikegami (Patriarch) on Aug 18, 2024 at 19:00 UTC

    Tip: Using typedef to create aliases of pointer types is generally frowned upon, especially when the name doesn't make it clear it's a pointer type.

    Better:

    typedef struct acme { int data; } acme;

    Taking this one step further, I wouldn't use an all-lowercase name so I could do something like Acme acme;.

      Yes sure.

      Unfortunately e.g. ctl then ends up with something like:

      … struct _host { int status; str name; }; typedef struct _host Host; // <- … deq_Host_push_back(&gizmo, (Host){301, str_init("joearms.github.io")}) +;

      Instead of deq_host_push_back in case of lowercase.

      Lowercase looks less perverted to me for the moment - but I am capable of learning.

        First of all, that's not what I recommended. You still naming the type struct _host which makes no sense.

        As for putting an uppercase "Host" in the middle of a function name, why would would do something silly like that. Or do you mean Host_push_back akin to Perl's Host::push_back? Definitely a gain since there's no equivalent to ::. Different things should look different.

        And you didn't say what you'd use instead of Host host;. What would the following look like in your system?

        Host host = Host_new();