1

I am new to C. I don't understand how to solve the last two lines of the following code, can you explain it? thank you very much.

pBuffcmd = (uint32_t*)&CmdBuffer[CmdBuffer_Index]; *pBuffcmd = cmd;

#DL_SIZE                  (8*1024L)
#define CMD_FIFO_SIZE     (4*1024L)
#define CMD_SIZE          (4)/

uint32_t CmdBuffer_Index;
volatile uint32_t DlBuffer_Index;

uint8_t  DlBuffer[DL_SIZE];
uint8_t  CmdBuffer[CMD_FIFO_SIZE];

void App_WrCoCmd_Buffer(Gpu_Hal_Context_t *phost,uint32_t cmd)
{
#ifdef  BUFFER_OPTIMIZATION

    uint32_t *pBuffcmd;

    if (CmdBuffer_Index >= CMD_FIFO_SIZE) 
    {
        if (CmdBuffer_Index > 0) {
            NOP;
        }
        CmdBuffer_Index = 0;
    }
    pBuffcmd = (uint32_t*)&CmdBuffer[CmdBuffer_Index];
    *pBuffcmd = cmd;
Luciano
  • 35
  • 4
  • In `pBuffcmd = (uint32_t*)...` is a _cast_ of what's on the right, to a _pointer_ to an _uint32_t_, which is an unsigned integer of size 32 bits, defined in `` – Paul Ogilvie Mar 26 '20 at 14:51

1 Answers1

3

(uint32_t*) is a cast. A cast is an operator that performs a conversion.

In this code, &CmdBuffer[CmdBuffer_Index] is a pointer to a particular element in CmdBuffer, and the type of that pointer is “pointer to uint8_t”, also written uint8_t *. This cast converts it to a pointer to a uint32_t, also written uint32_t *.

Then *pBuffcmd = cmd; attempts to write the value cmd to the uint32_t pointed to by the converted pointer.

This is bad code. The C standard does not guarantee that converting a uint8_t * to a uint32_t * will work. Even if that does work, the C standard does not guarantee that using a uint32_t reference to write to bytes in an array defined with element type uint8_t will work. It may be this code is designed for a particular C implementation in which that will work, but the desired result could be obtained using standard C code:

memcpy(&CmdBuffer[CmdBuffer_Index], &cmd, sizeof cmd);
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Color me genuinely puzzled, why wouldn't one be able to treat a vector of octets as a vector of double words of 4 octets each? And how would a C standard guarantee or fail to guarantee that this would work? The array is a memory area, filled consecutively, there is no structures or packing involved, just a sequence of octets, no padding, nothing else -- are you implying there may be address alignment issues? – Armen Michaeli Mar 26 '20 at 15:03
  • @amn - with few exceptions, the C standard doesn't guarantee that pointers to different types have the same representation or alignment requirements, and converting pointer values to different types may not preserve the original pointer value. In practice, any implementation that offers `uint8_t` and `uint32_t` will *most likely* execute this code as expected, but it's simply not guaranteed. – John Bode Mar 26 '20 at 15:14
  • 2
    @amn: C 2018 6.3.2.3 7 says “A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined…” Since `CmdBuffer` is an array of `uint8_t`, the compiler may locate it anywhere, with no particular alignment, and so the address `&CmdBuffer[CmdBuffer_Index]` may similarly be located anywhere. But `uint32_t` commonly has an alignment requirement of four bytes, in which case the behavior of the conversion to `uint32_t *` may not be defined by the C standard. – Eric Postpischil Mar 26 '20 at 15:29
  • @JohnBode *In practice, any implementation that offers `uint8_t` and `uint32_t` will most likely execute this code as expected* Only for extremely generous interpretations of "most likely": https://www.google.com/search?q=arm+sigbus+site:stackoverflow.com Even x86 isn't totally immune to alignment issues: https://stackoverflow.com/questions/46790550/c-undefined-behavior-strict-aliasing-rule-or-incorrect-alignment/46790815#46790815 – Andrew Henle Mar 26 '20 at 15:31
  • @amn: C 2018 6.5 7 says objects shall be accessed only via certain types, notably types compatible with their declarations and various special cases. Since `CmdBuffer` is defined as an array of `uint8_t`, accessing it with a type of `uint32_t` violates that rule, with the consequence that the resulting behavior is not defined by the C standard… – Eric Postpischil Mar 26 '20 at 15:31
  • … C compilers commonly use this rule in 6.5 7 to know that proper code is not accessing objects through different types. E.g., if a routine is passed a `float *x` and an `int *y`, it knows that no `y[i] = foo;` in a loop can change any `x[j]`, and that allows various optimizations. – Eric Postpischil Mar 26 '20 at 15:31
  • 1
    @amn: The rule about conversion of pointers is an accommodation to C implementations with unusual memory spaces and different representations for pointers of different types. You are less likely to encounter problems with it in modern C implementations, but the rule remains. – Eric Postpischil Mar 26 '20 at 15:33
  • Thank you for elaborating on this, everyone. – Armen Michaeli Mar 26 '20 at 16:56
  • UV for the answer and the comments. – chux - Reinstate Monica Mar 26 '20 at 18:02