0

I've been doing some practicing in C with dynamic memory allocations and pointers. I tried printing out random variables to see how it all works.
It works printing out chars and ints but for some reason no matter what I try I can't print out the float value I desire.
I tried manually typing pi, I tried using the constant from math.h. It prints out a huge totally random number and I am completely baffled as to why it doesn't work.
I tried printf("%f\n", (float) memory[3])) and printf("%f\n", (float) *(float *)&memory[3])) but it doesnt work.

uint16_t* rezerviraj(int sizeToAllocate){

    uint16_t *reservedSpace = malloc(sizeToAllocate + 4 * sizeof(char) + sizeof(float) + sizeof(int32_t));
    memset(reservedSpace, 23246, sizeToAllocate);

    return reservedSpace;
}

void brisi(uint16_t* pomnilnik){
    free(pomnilnik);

}

uint16_t* vstavi(uint16_t* memory){
    *(char *)&memory[0] = 'X';
    *(char *)&memory[1] = 'P';
    *(char *)&memory[2] = 'O';
    *(float *)&memory[3] =  3.141312;
    *(int32_t *)&memory[4] = 23246;
    *(char *)&memory[5] = '!';

    return memory;
}

void print(uint16_t* pomnilnik){
    printf("%c  \n", (char) *(char *)&memory[0]);
    printf("%c \n", (char) *(char *)&memory[1]);
    printf("%c  \n", (char) *(char *)&memory[2]);
    printf("%f\n", (float) memory[3]);
    printf("%d  \n", memory[4]);
    printf("%c \n", (char) *(char *)&memory[5]);

}

int main() {

   uint16_t *test= (uint16_t*) rezerviraj(500);
   test = vstavi(test);
   print(test);
   brisi(test);

    return 0;
}

Jack Lilhammers
  • 1,084
  • 4
  • 16
Banka Don
  • 31
  • 4
  • 4
    A `float` takes up more than 16 bits – Hong Ooi Mar 24 '21 at 08:56
  • 2
    Why don't you define a struct for your data? – Jack Lilhammers Mar 24 '21 at 08:57
  • 2
    Supposing `*(int32_t *)&memory[4] = 23246;` "works" (the statement is UB), it doesn't do what you think it does; it writes `90` or `206` (`23246 = 90*256 + 206`) to `memory[4]` and `206` or `90` to `memory[5]`. – pmg Mar 24 '21 at 08:59
  • 4
    C or C++? They are very different languages. – molbdnilo Mar 24 '21 at 08:59
  • 2
    `*(int32_t *)&memory[4]` accesses 2 bytes after `memory[3]`. Casting to `int32_t *` means that it will write 4 bytes from `&memory[4]`, overwriting memory[5] – Jack Lilhammers Mar 24 '21 at 09:03
  • 1
    Related: https://stackoverflow.com/questions/44137442/what-is-type-punning-what-is-the-purpose-of-itwhat-happens-if-i-use-it-or-not and https://stackoverflow.com/questions/17789928/whats-a-proper-way-of-type-punning-a-float-to-an-int-and-vice-versa . Also, are you aware that different types may have different sizes? – Bob__ Mar 24 '21 at 09:04
  • 5
    Code such as `*(float *)&memory[3] = 3.141312;` are [strict-aliasing violations](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) and undefined behavior. You can ***not*** safely cram a `float` or an `int32_t` into any part of a `char` array. Accesses like that are also undefined behavior because of alignment restrictions. Anyone who says anything like, "But it works" [doesn't know what they're talking about](https://stackoverflow.com/questions/47510783/why-does-unaligned-access-to-mmaped-memory-sometimes-segfault-on-amd64). It just hasn't failed for them. Yet. – Andrew Henle Mar 24 '21 at 09:31
  • 1
    This assignment `*(int32_t *)&memory[4] = 23246` will overwrite the last two bytes of the float (usually 4 bytes) holding pi. As others have commented, there are many things wrong in your approach, but this is the practical reason why you see a strange value for pi. – nielsen Mar 24 '21 at 09:55
  • 1
    @AndrewHenle I don't want to defend this code too much, because there is a lot of bad things happening. But, I don't think think that float assignment is necessarily SA violation because object is allocated with `malloc` and thus has no declared type (it's not `char` array). I may be wrong tho, effective type rules are so complex and I don't know if `memset` affects it also. – user694733 Mar 24 '21 at 10:15

0 Answers0