3 ms·
Not to be a downer, but this is poor and outdated C programming style. Don't use sbrk(2) unless you're completely reimplementing the standard library. Don't u
by colanderman 10y ago
Not to be a downer, but this is poor and outdated C programming style.
Don't use sbrk(2) unless you're completely reimplementing the standard library.
Don't use alloca(3) unless you want weird headaches. Just use dynamically-sized arrays, which have been present in C for nearly two decades. They are block-scoped and easier to reason about.
None of the magic numbers are explained. `(p->si_addr + (16LL<<22)) & ~4095`, where do those come from? I'm guessing 4095 is the page size less one, but DON'T hardcode that!
Don't assign to lvalues in conditionals! (e.g. `while(j<31 && !(h=free_table[j]))`) It's hard to read and bug-prone.
Don't use `&h[1]` to refer to the space after a structure. I'm pretty sure that's undefined behavior, and it often gives the wrong alignment for whatever you want to put after h. Rather, add a final element to the structure of flexible array type (say `int data[]` if you're storing ints after the structure). That is guaranteed to have the semantics you're looking for.
Here's my advice:
1) Just use malloc(3). It's already fast and tuned to many allocation scenarios (including all four in this article!), and your application will continue to reap whatever performance improvements its maintainers make. Use aligned_alloc(3) if you need pages.
2) When working in the embedded world, it's often preferable to preallocate pools as large as your app will ever need for each kind of object you have collections of, and pin them to RAM (not necessarily for performance, but so you know you have the space). If you do so, you can reference the objects by index rather than pointer. It's much faster and more space-efficient, especially on 64-bit architectures.
3) Don't be afraid to realloc(3) to grow arrays. It incurs no asymptotic penalty.
4) Pay attention to data layout, to make sure that commonly-accessed stuff is not interspersed with rarely-accessed stuff. E.g. separate indexes from data where possible, if you tend to traverse the index rather than the data.
(Caveat: all my comments above apply to glibc. YMWV on other systems.)
- akira2501 10y ago> Don't use `&h[1]` to refer to the space after a structure. I'm pretty sure that's undefined behavior Not defending the code, but it isn't undefined. Pointers to "one past the last element of an array" are a special case and have specific/defined behavior in the standard.
- colanderman 10y agoYou are correct, and I was right to doubt my memory. Though my point about misalignment stands.
- cperciva 10y agoDon't use `&h[1]` to refer to the space after a structure. I'm pretty sure that's undefined behavior This is legal. '&h[1]' is a synonym for 'h + 1', thanks to C99 section 6.5.3.2 paragraph 3: ... if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator.) and that is valid thanks to C99 section 6.5.6, paragraphs 7 and 8: 7. For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type. 8. When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. [...] Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object [...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated. So is 'h' points to an object it is entirely legal to compute '&h[1]'; whether you can dereference it is a separate question (and will depend on memory layout et cetera).
- colanderman 10y agoAh, I forgot that "one past the last element" is excepted. I stand corrected. (Similar tricks, such as &h[-1], are indeed undefined behavior.) Regardless, my point stands that it can give you the wrong alignment, if the elements you're putting after the header have greater alignment requirements than the header itself. E.g.: #include <stdint.h> struct foo { uint16_t a,b,c; } uint64_t *bar(struct foo *x) { return (uint64_t *) &x[1]; } Gives you a misaligned pointer to an 8-byte object. #include <stdint.h> #include <stdint.h> struct foo { uint16_t a,b,c; uint64_t d[]; } uint64_t *bar(struct foo *x) { return x->d; } That gives you a properly aligned pointer.