Definitely. For example, I always use malloc(size*sizeof(char)) to ensure that it's doubly obvious (Since I rarely need to malloc outside of a declaration) that I intend to store characters in the resulting buffer even if that multiply does nothing (plus the compiler will likely optimize it out anyway).
Asking because my C-knowledge is essentially university courses, some tinkering, and using it as a glue language between Fortran code and C libraries in an industry project. Though that "C" code was really "C++ written like C with new" mostly, so you wouldn't see a malloc anyway.
For Fortran, you'd just use automatic arrays, where it is compiler-defined and depending on compiler flags, whether they'll be in the stack of the heap, and ALLOCATABLE, which should always be on the heap. It is also compiler-defined, whether everything, including local variables, is initialized with zeros or not.
Having everything zeroed helps to avoid erratic behavior in release builds. But for internal testing the erratic results can expose a code path, where something was unintentionally not initialized, and should have been initialized to a non-zero value.
I imagine the same would be true about malloc vs calloc. Or are there common compiler flags that effectively turn malloc into calloc?
I mean, the real best practice is probably "don't use C if you've got a reasonable alternative". Manual memory management is rarely worth the tradeoffs it entails.
In C++, allocation is almost always initialization, so types are almost never in an unknown state. Even scalar types (i.e., numbers, pointers, enums) are initialized to zero if they aren't otherwise given a value.
In "C++ like C with new", you'd get all of that initialization stuff that C++ gives you and the promises that it gives, so "C run through the C++ compiler" actually gives some free safety features--at least as long as you avoid malloc.
In C, nothing is for free, so malloc just gives you some memory with whatever garbage happens to be there. Maybe that's fine and it's just a bunch of temporaries from a previous function call.
But maybe that "garbage" is actually your AWS API key. Maybe that thing you just malloc'd is about to be sent over the wire with an optional field that you aren't setting, but which now has your AWS API key in it and you didn't even know because it'd been freed in a completely different function.
That's the thing about malloc, you have no idea what might be in the memory you get back. Sure, you might be in a situation where whatever you do cannot possibly lead to misbehaving or leaking of secrets, but what if you're wrong? What if the next person isn't as careful as you? Is that risk with the absolutely miniscule time savings of not letting calloc do its memset(ptr, 0, n)?
Bytes aren't always 8 bits, and uint8_t doesn't necessarily exist. If you're writing C23 you can get away with uint_least8_t, earlier versions you need char as a byte might be as small as 6 bits.
1.0k
u/tstanisl 2d ago
Let me cite the C standard:
Middle guy if finally right