Likely not. Malloc guarantees that the passed-in size is the minimum number of bytes it allocates, but not the maximum. You’d likely get some minimum sized chunk, somewhere between 16-32 bytes depending on the system as far as I understand it.
Implementations are allowed to specify behavior that is otherwise undefined.
I looked up a C24 draft and it's actually stricter:
The pointer returned if the allocation succeeds is
suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental
alignment requirement and size less than or equal to the size requested.
So a pointer returned by malloc(1) is not necessarily valid for int*.
The actual allocated size is much bigger anyways, but it will be a multiple of 8 bytes on a 64 bit system, and 'usable' part of that will be at least 8 bytes, and typically you will be able to read at least 16 without a page fault.
Malloc can return a null pointer if the operation fails. This can be the case if, afaik, for example, there is no more heap available and the OS is not capable of swapping or freeing some other memory for some reason
has it always been valid? I could have sworn that freeing a nullpointer was only valid in C++ but not in C. I couldn't find anything on cppreference on when this was introduced or if it has always been like this
Very certain you could always free(NULL); in C. In fact, it's good practice to set pointers to NULL after freeing them to avoid issues like double-free.
Uuuh... Actually 🤓🤓☝️☝️☝️ an int isn't 4 bytes, it's platform/compiler dependent. Assuming an int is 4 bytes will be in the majority of cases true, but it's not always the case
We need to define terms more precisely. sizeof(char) will always be 1. But on some platforms, char is not an 8-bit type. It could actually be a 32 bit type. The c programming language does not (I believe) acknowledge or define what a byte is. But if it is an 8 bit integer type, then char will not always be one byte.
It may be better to say "octet" instead of "byte" in this type of discussion.
The implementation has to define CHAR_BIT in <limits.h>. CHAR_BIT is the number of bits in variables of type "char".
Fun fact, C does use the term byte all over the standard. And it is well defined. Byte is defined to be the unit that sizeof(char) is measured in. When the standard refers to bytes, they are referring to atomic divisions of memory in chunks of char.
Which does not necessarily need to be the same as an architectural byte. C requires only that their definition of byte is at least 8 bits (possibly more) and an addressable unit of memory - meaning it is some multiple of architectural bytes. Though on every platform still in use today, and not a historic curio, that multiple is 1.
So I am wrong about that. Oops. I guess then that one needs to define what they mean by "byte" when using it in an online discussion. The person I replied to is right, then, that char will always be one byte. But some people when they say "byte" are thinking of an 8-bit entity. Anyway, thanks for the info.
You're brobably right. To be honest, I keep confusing myself with bytes and bit cause I'm french and here we use octet.
Plus, my C classes starts getting quite far, but I just remembered the fun fact, I'll go check properly because it actually made me curious.
It's kinda funny that C99 introduced int8_t and made it optional, but I'm sure there's some good reason. Basically if that type exists, then CHAR_BIT is 8. Also POSIX.1-2001 defines it that way, so most people can safely assume it.
I read it as the size of the pointer being 4 bytes, but now I see you were referring to the int. AFAIK the size of int is specified as "at least" 32 bit in the C standard, and all 32 and 64 bit platforms I know indeed use 32 bit. Though the size of long (not speaking of long long) is different on different 64 bit platforms, IIRC. Windows uses 32 bit and Linux uses 64. Both use 64 for long long. I prefer to use (u)int*_t when I need to be sure about the size and I use int/size_t/time_t/... when I interface with functions that use those in their signature.
The size of char (which is interchangeable with the size of a byte) is specified in old standards as large enough to a) be addressable without bit manipulations and b) hold the full C source character set, which need not be case sensitive and may rely on trigraphs. In practice, this comes out to at least 6 bits. In newer standards I believe it's specified as at least 8 bits.
The size of int short is at least and a multiple of that of char, the size of int is at least that of int short and a multiple of that of char, and so on.
So in theory, a conforming C implementation could have 6 bit ints.
wchar_t is messy, in large part because Windows was one of the earliest Unicode adopters. It's meant to be able to support any "wide" character, which means that it's supposed to be determined by the character pages the platform allows (and implicitly, should be 32 bits if any version of Unicode is supported, since Unicode is technically a 32-bit format regardless of encoding), but Windows adopting Unicode while it was still 16-bit UCS-2 and locking wchar_t down as a result meant that it was impossible for wchar_t to actually meet its requirements on Windows. ...Which meant that its minimum size requirement ended up being removed.
So, now its requirement is just "holds wide characters, check your implementation. Please don't use it."
Assuming 8-bit bytes, sizeof(int) is guaranteed to be a minimum of two, and intended to be the system's word size (which should technically be 8 for 64-bit platforms, but we're so used to 32-bit int that most platforms intentionally stagnate int at 32 bits & most processors have two native word sizes to accomodate), but can be anything higher. ILP64 models have 64-bit int, and there was at least one platform where all bytes were 64-bit and sizeof(char) == sizeof(long long) == 1, though, so it can get weird sometimes.
(Also, as a note, long long is required to be at least 64 bits. long is required to be at least 32 bits, and is meant to just be the 32-bit data type, but ends up being the design limitation fulcrum for most platforms; Windows is locked into 32-bit long because it needs to support 32-bit executables, and Linux is locked into 64-bit long because it needs to support punning pointers to long.)
344
u/AdBrave2400 2d ago
Is the mistake that they're allocating 1 byte and storing in a pointer to an int which is 4 bytes?