4 ms·
One problem is, in C at least, the compiler has no way to know that the contents pointed to by p have reached their end of life. All these examples use malloc()
by dwarman 11y ago
One problem is, in C at least, the compiler has no way to know that the contents pointed to by p have reached their end of life. All these examples use malloc() and free(), but these two names are purely convention, and any names and memory management methods can be used with different names. And implications for the contents.
But there is another problem too - the free() might (should:) use a mutex while it does its work, but another thread could be woken up during the free() postamble, after the mutex has been released but before the caller resumes execution - or even between the == comparison and the second free() - call malloc(), and the implementation might be one that re-uses the most recent free(). Which would mess up the other thread wonderfully.
Neither of the above rely on any kind of mapping between the C variable p and the underlying hardware. This is deliberate. C is defined as an abstract grammar and semantics set, primarily because by that era it was painfully recognised that inventing new HLL's for each new hardware architecture was a losing proposition. There were so many of them, and those languages were not transportable. The essence beauty of C was it is simple enough to be implemented on any level from direct hardware out to as many layers of VM as one could wish for. And really only required the execution machine model to be Turing complete. Its early use was all done to the metal, hence the inherited impression that C pointers are hardware pointers, but really only when used at the metal is this likely to be true. And typically, these days, one finds architectural specific extensions, such as intrinsics, that allow metal access from C to the custom parts of the hardware.
The still painful part of C though is where its architectural independence intrudes. Such as, sizeof(int) being the native hardware size of an integer. 8, 16, 24, 32, 36, 48, 64, I've suffered from them all. Similarly, sizeof(enum) is undefined. The language only stats it must be large enough to represent all its values. I have found the compiler definition differences of bool to also be very frustrating. I grew into software from a hardware design background, and to me
a & true == a
is always true. Or should be. The language defines boolean values as 0 for false and any other value for true. Most compilers choose 1 for true - enum style. So then
((a & true) == a) && ((a == 0) || (a == 1))
Useless when trying to deal with metal and bitflag registers (clearly not the literal true, rather when somewhere else a variable has been set to true and later is used as a mask).
Some compilers have compile command options or #pragmas for forcing the issue, but there is no standard for these. Still. These indefinites can cause serious and sometimes difficult to debug problems when the binary structures containing these things have to be shared between different architectures. Not to mention endian-ness.
All told though, C is still easier than ASM, which usually _is_ specific to the hardware architecture.
- dllthomas 11y ago"One problem is, in C at least, the compiler has no way to know that the contents pointed to by p have reached their end of life. All these examples use malloc() and free(), but these two names are purely convention, and any names and memory management methods can be used with different names." This seams wrong, unless by "purely convention" you mean in some sense that the entire standard is "purely convention". The clearly defines the lifetime of an allocated object to be from allocation to deallocation, and clearly labels free (and realloc, in some circumstances) as deallocating. I am not sure whether a conforming implementation can introduce new functions that also, in the sense of the standard, deallocate, but in either case the provided code is still technically incorrect per the standard. "Such as, sizeof(int) being the native hardware size of an integer. 8, 16, 24, 32, 36, 48, 64, I've suffered from them all." Nit, and I'm sure you're aware, but perhaps worth noting for others: the values you're listing are (I infer) number of bits, which is not the same as what's returned by sizeof. sizeof gives number of chars, which on some architectures has actually been other than 8 bits!
- dwarman 11y agoBut does not define them in terms of hardware. My numbers referred to the native widths of the hardware words. sizeof(int) would of course return those numbers divided by 8, but machines are almost universally referred to by bit width, not byte width. Intel 64 bit chips, not Intel 8 byte chips, for example. So sizeof(int) is still a function of hardware width, and hardware width is defined in terms of bits. Perhaps I should have been a bit more specific, instead of leaping over fully internalized transforms without explanation? Here? In a discussion about hardware? And note that 36 bits is not a multiple of 8, which actually breaks sizeof() anyway.
- dllthomas 11y ago"Perhaps I should have been a bit more specific, instead of leaping over fully internalized transforms without explanation?" I don't know about "should" - my post wasn't really meant as criticism. I just thought we had an opportunity to dig in a little deeper and do so a little clearer. "Here? In a discussion about hardware?" There are a whole lot of people here who have only done web dev or high-level x86 application development, and many who are only passingly familiar with C or HW. "And note that 36 bits is not a multiple of 8, which actually breaks sizeof() anyway." Oh, a 36 bit architecture without a char size of 9? Interesting! How did that work? Can that be standard conforming?