5

I have the below code:

#include <inttypes.h>
#include <stdlib.h>
struct a
{
  void *p;
};

int main(void)
{
  struct a *ptr = malloc(sizeof(struct a));
  ptr->p = malloc(sizeof(uint8_t));
  *((uint8_t *) ptr->p) = 2;
  return 0;
}

I am casting the void pointer before dereferencing to avoid the warning

warning: dereferencing ‘void *’ pointer

Am I breaking any rule by doing this or is this code good?

M.M
  • 138,810
  • 21
  • 208
  • 365
Gopi
  • 19,784
  • 4
  • 24
  • 36
  • What suspicions do you have about rules that might be broken? – M.M Jul 28 '15 at 06:09
  • 2
    If there's no specific reason why the type of `p` isn't just `uint8_t*`, this is terrible code. – Staven Jul 28 '15 at 06:09
  • @MattMcNabb casting the modifiable lvalue? Just wanted to confirm once that this is good or not? – Gopi Jul 28 '15 at 06:10
  • 2
    @Staven Sir this is not the actual code I have in my repo.. Just trying to do something like this. Assume there is already a `void *p` in the stricture and that structure can't be disturbed but want to use it.. This is not a terrible code – Gopi Jul 28 '15 at 06:11
  • 2
    You should `#include ` – M.M Jul 28 '15 at 06:12
  • @MattMcNabb yes sir that care is taken. Casting lvalue was my question and you answered it thanks – Gopi Jul 28 '15 at 06:13
  • @Gopi technically my answer is wrong if you didn't, so it would be good to update your question to include it – M.M Jul 28 '15 at 06:14
  • @MattMcNabb Yes edited my question – Gopi Jul 28 '15 at 06:15
  • `uint8_t` should come with `inttypes.h`, btw. – alk Jul 28 '15 at 06:16
  • @alk Agree.. My question is mostly on the casting part. Yes headers are needed :) – Gopi Jul 28 '15 at 06:19

2 Answers2

6

Yes this code is legal and does not cause undefined behaviour (unless malloc returns NULL).

M.M
  • 138,810
  • 21
  • 208
  • 365
3

As per the standard mandates, this code looks ok. a pointer to a character type can be used to point to the object without breaking the aliasing rule.

To quote the standard, chapter §6.3.2.3

[...]. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    The code would be OK even if it were not a pointer to character type. Since the object has no declared type, the *effective type* for writing is the type you are using to write with, (and the effective type for reading is the type of the last thing written to the object). We only write in this example, so we set the effective type. – M.M Jul 28 '15 at 06:35
  • @MattMcNabb Absolutely sir. I was thinking like if `p` had not been a `void *`, then also, casting to `char *` (or equivalent) and further usage would be defined, right? – Sourav Ghosh Jul 28 '15 at 06:38
  • nb: I think uint8_t is not neccessarily character type (http://stackoverflow.com/questions/12666146/can-uint8-t-be-a-non-character-type) – Giorgi Moniava Jul 28 '15 at 06:39
  • @SouravGhosh the type of `p` doesn't matter; the type of the object matters. The object was created by `malloc` so it has no type. – M.M Jul 28 '15 at 06:42
  • @MattMcNabb sorry sir, got a bit confused. I thought the type of `p` matters other than being `void *`. Like, if we have `float *p = malloc(sizeof*p);` and then we do `*((int *)p) = 5;` is that case defined? – Sourav Ghosh Jul 28 '15 at 06:49
  • @SouravGhosh Yes that is well-defined , so long as `sizeof(int) <= sizeof(float)`. Writing through `*(int *)p` sets the *effective type* of the object allocated by `malloc` to be `int`. It would be undefined to read `*p` subsequently. – M.M Jul 28 '15 at 06:52