1

I'm trying to write 4 bytes, but then increment pointer by only 3 bytes, and write another 4 bytes (overwriting the last byte), but everything ive tried inc's the ptr by 1 or 4, and I have a feeling even if I jinxed it it probably wouldn't be the best method. How to specifically increment by 3, and what is the recommended approach? It seems that using a (char *) cast might be the way to go?

 uint32_t value = 0x00112233;
 uint32_t *ptr = (buffertowrite);
 *ptr = value;  // write 4 bytes
 ptr += 3;      // but only move forward 3 bytes
 *ptr = value;  // write next 4 bytes (overwriting the last byte)

2 Answers2

4

Remember that C11 is a programming language, so is a specification (it is not a software). Read n1570 draft.

How to specifically increment by 3, and what is the recommended approach? It seems that using a (char *) cast might be the way to go?

That is very probably some undefined behavior (in general). On some computers, it might "work" (but very slowly, because you make an unaligned access, read about data structure alignment). You could try;

ptr = (uint32_t*)((char*)ptr + 3);

But you should avoid coding like that (it is some ugly non-portable code, with bad smell). On many computer architectures or instruction sets, you are likely to get a bus error or a segmentation fault. On some computers where that is not crashing, it might be a non-atomic operation (you might not be sure of what would happen if that code was scheduled so got a context switch or some interrupt inside). Read also about sequence points & pointer aliasing.

So I recommend not coding like that, even if it happens to apparently work (a future optimizing compiler might do things differently) on your machine. If you need to code such bad things, be sure to at least add a big fat warning in some comment. Perhaps use volatile (or some atomic operations). Be sure to check the emitted assembler code (e.g. with gcc -O -fverbose-asm -S).

(a less ugly solution might be to copy byte by byte)

Take time to read Lattner's blog on What every C programmer should know about undefined behavior; you really need to read that carefully.

(not getting any warnings, and getting some apparently working code, is the worst kind of undefined behavior; you should be very scared, and you are not scared enough!)

Since you are thinking from some piece of code in assembler, you might consider using an asm statement. Read Using Assembly Language with C.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    But where is the fun in that ;) – cdcdcd Feb 13 '17 at 12:23
  • I agree that too much casting could easily lead to pointer aliasing and thereby undefined behavior. Good answer as always Basile. – Morten Jensen Feb 13 '17 at 12:34
  • Basile thankyou! I tried a lot of variations in that ballpark but no luck, but with your help i'm not even getting any warnings so it's looking good! Thanks again – Kerry Daniels Feb 13 '17 at 12:35
  • No it is not looking good. It is smelling very bad. You are not ashamed enough. – Basile Starynkevitch Feb 13 '17 at 12:36
  • Geez, Basile I don't think he's writing the landing system for an aeroplane. Mucking around like this how you learn. And if he/she wants to implement an aligned version of malloc this is much needed understanding. – cdcdcd Feb 13 '17 at 12:51
  • But in 6 months when he has upgraded his compiler the behavior is likely to be different – Basile Starynkevitch Feb 13 '17 at 12:52
  • But not in the way it accesses the individual bytes. Look it is crazy what they're doing but I think it is more of learning exercise. Building with optimisation is often fraught with dangers even if you follow the C standard. The compiler can do some crazy things if you don't tell it exactly where and what needs to be optimised. – cdcdcd Feb 13 '17 at 13:04
  • It's perfectly valid (it seems?) in x86 to do (for example) "mov [eax], cl" then "inc eax" to move ptr+1 then "mov [eax], cl" etc to repeatedly fill a buffer one byte at a time - obviously 3 out of 4 of these single byte writes will not be aligned, but the CPU allows it, so I'm confused why "(char *)ptr+3" in C is so "bad"? cdcdcd yes I'm just trying to learn because i find this very interesting and if i think it's important to know how to (and not) do fundamental things like memory i/o, and making mistakes and learning why they're 'bad' etc is a healthy part of the process! – Kerry Daniels Feb 13 '17 at 23:43
  • But C is not x86. It provides an abstraction layer, and the compiler takes advantage of that by doing optimization. – Basile Starynkevitch Feb 14 '17 at 05:33
-1
  1. If it's bytes you're talking about, then you should work with bytes, or something of uint8_t type instead of uint32_t.

  2. Looking at your types I'd say this

    uint32_t *ptr = (buffertowrite);
    ptr += 3;      // but only move forward 3 bytes
    

    is pretty wrong. Pointer arithmetics will move the pointer 3*sizeof(uint32_t) bytes forward.

Igor S.K.
  • 999
  • 6
  • 17