4

Many modern architectures use type with all bits set to zero, in which case:

void *p;
memset(&p, 0, sizeof(p));
assert(p == NULL); /* assertion holds on most architectures */

Just to be fully compliant I also explicitly set all pointers inside allocated struct to NULL. In case I directly call calloc (or any proxy function using calloc), compiler can figure out that calloc-allocated memory is already zeroed properly for x86's NULL and simply removes explicit NULL assignments, but in case I use a function pointer to calloc it obviously can't deduce it. How can I hint gcc (or MSVC) that these assignments can be removed safely?

Code example:

struct s *p = calloc(1, sizeof(*p));
p->ptr = NULL; /* optimized out */

calloc_ptr calloc_f = ...; /* points to calloc */
struct s *p = calloc_f(1, sizeof(*p));
p->ptr = NULL; /* isn't optimized out because compiler can't assume p's memory is already set to 0 */
Wirtos_new
  • 41
  • 1
  • 2
  • Why do you need this hint? What is the problem you have with the code you show? If you have a question that involves build messages, then please include the commands you use to build (or the flags/options set in the IDE) as well as the actual build output. Also please take some time to read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). Lastly please learn how to [edit] your questions. – Some programmer dude Jul 13 '21 at 18:33
  • GCC have many compiler-specific *attributes* that can be set on functions, variables and structures. There might be one which tells the compiler that the function sets all data to zero? If you find the declaration of e.g. `calloc` perhaps you can see if it has some GCC-specific attribute set? Or perhaps go through [the function attributes documentation](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html)? – Some programmer dude Jul 13 '21 at 18:40
  • 1
    @Some programmer dude, Re "*If you find the declaration of e.g. `calloc`*", Ubuntu's `/usr/include/malloc.h` has `extern void *calloc (size_t __nmemb, size_t __size) __THROW __attribute_malloc__ __wur;`. Not sure what those mean, but `malloc` has the same ones (`extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;`), so they're not relevant. – ikegami Jul 13 '21 at 18:45
  • @Someprogrammerdude I've tried to search for such attribute, but no luck. Calloc uses general attribute((malloc)) which isn't what I want. Moreover, these attributes don't work on a function pointer variable, which calloc_f is. – Wirtos_new Jul 13 '21 at 18:47
  • Then the compiler might just have specific recognition of these functions, similar to how it can replace e.g. `memset` with target-specific versions of the function. – Some programmer dude Jul 13 '21 at 19:00
  • 2
    I'm afraid you might have to come up with architecture-specific defines, and place the code between and `#ifndef CALLOC_SETS_NULL` and `#endif`. You could have the build system try to check if `calloc` results in `NULL` as you did in the first few lines of code, and then pass `-DCALLOC_SETS_NULL` to the compiler. – Cheatah Jul 13 '21 at 19:11
  • @Cheatah that's what I came up with too, but it's not very elegant and requires the buildsystem to test specific architecture behaviour before building the code. – Wirtos_new Jul 13 '21 at 19:15
  • 2
    I believe GCC currently reserves some special treatment based on name. The mechanism seems to involve internally replacing certain libc functions calls with __builtin_FUNCTIONNAME and this can be suppressed with `-fno-builtin` or `-fno-builtin-FUNCTIONNAME` (`-fno-builtin-calloc`) (https://gcc.godbolt.org/z/cvdn3bxex) (all this is described in the official docs), but it sure would be nice if instead of this weirdness, you could apply the special libc-function-like optimization semantics to functions that are custom-named. – Petr Skocik Jul 13 '21 at 19:19
  • 1
    @Wirtos_new If you worry about `(void*){NULL} `not being all-bits/bytes 0, then you could simply write an inline test for it and then do `if (!NULL_IS_ALLBITS0()) r->ptr = 0;`. Here's a simple one that both gcc and clang treat as a comptime constant even though it's not an integer constant expression per se: https://gcc.godbolt.org/z/9dKbKh8Kz – Petr Skocik Jul 13 '21 at 20:07
  • @Wirtos_new I already assumed so, and I agree it's not elegant. – Cheatah Jul 14 '21 at 02:05

0 Answers0