cancel
Showing results for 
Search instead for 
Did you mean: 

How do I declare an array of structs with one element a byte aligned array of uint8_t

magene
Senior II

I'm trying to clean up some code I used to figure out how to use the UARTs on a STM32H7A3. The STM examples declares the data to be sent out like this:

ALIGN_32BYTES(uint8_t txBuffer[]) = " *****UART_TwoBoards comm ... ";

ALIGN_32BYTES is defined like this #define ALIGN_32BYTES(buf) buf __attribute__ ((aligned (32))) 

I'd like to declare an array of struct like this:

struct Commands //TODO this should be const

{

uint8_t numBytes;

uint32_t timeout;

uint8_t cmd[];

};

Commands commands[numCmds];

but this: ALIGN_32BYTES(uint8_t command[PUBX00].cmd[]) = "$PUBX,00*33\r\n";

gives this error at the . between [PUBX00] and cmd[]

[Clang IntelliSense] Error: expected ';'

Any ideas how to fix this will be greatly appreciated

1 ACCEPTED SOLUTION

Accepted Solutions

> I took that to mean I could have 1 variable length array in a struct as long as it was the last element in the struct and I defined it later in the program. Is that wrong?

Yes, it is incorrect. You can't have variable-length members of a struct.

> I was thinking I just didn't know how to make the ALIGN_32BYTES macro work with an array of structs with an array as one element of the struct.

Remove the ALIGN_32BYTES macro from it and you'll find you get the same error. You can't assign strings like you can with, say, integers.

> Regardless, I think this is a case of me trying something fancy without knowing enough C++ to pull it off. I'll work on a simpler approach.

I would tend to agree. I don't think you need things aligned to a 32-byte boundary here at all. I'm guessing the example might be using DMA and is trying to avoid cache issues. If your structure is const, you don't need to worry about this at all since it will be stored in flash and never change. But you need to define it all at once rather than doing it later on in the program.

struct CommandStruct {
  uint8_t numBytes;
  uint32_t timeout;
  const char * cmd;
};
 
const CommandStruct commands[3] = {
    {5, 100, "hello"},
    {6, 100, " world"},
    {1, 100, "!"}};

Or just store the strings and use strlen() to get the length.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

6 REPLIES 6
TDK
Guru

You have a few issues here that have nothing to do with alignment. You can't have a variable length array within a struct. You can have a pointer, and have it point to something else that is aligned.

> uint8_t command[PUBX00].cmd[] = "$PUBX,00*33\r\n";

This isn't valid syntax even without the alignment. Strings are copied with strcpy, but again, you can't have a variable length array in a struct. How would the compiler know how much memory to allocate for each member?

If you feel a post has answered your question, please click "Accept as Solution".
magene
Senior II

Thanks for the response. I'm definitely learning as I go and there's plenty of things I don't know. I'm using VisualGDB with C++11 with GNU extensions (-std=gnu++11) as the language standard. If I put the uint8_t cmd[] line anywhere but the last line in the struct, I get this compiler error: "[Clang IntelliSense] Error: flexible array member 'cmd[] ' with type 'uint8_t' is not at the end of struct". I took that to mean I could have 1 variable length array in a struct as long as it was the last element in the struct and I defined it later in the program. Is that wrong?

In addition, I get the same error (which is actually "[Clang IntelliSense] Error: expected ';' at end of declaration") if I do this in the struct: uint8_t cmd[3]; and this when I try to align cmd: ALIGN_32BYTES(uint8_t commands[PUBX00].cmd[]) = "abc"; I was thinking I just didn't know how to make the ALIGN_32BYTES macro work with an array of structs with an array as one element of the struct.

Regardless, I think this is a case of me trying something fancy without knowing enough C++ to pull it off. I'll work on a simpler approach.

alister
Lead

>... examples

You would want to trust what is teaching you.

Poor teaching would only make you a worse programmer.

Are you using C11? http://www.open-std.org/JTC1/SC22/WG14/

The published standard must be purchased.

An earlier working document is at http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf.

Especially in embedded, you may have to use compiler-specific extensions.

Are you using GCC? https://www.gnu.org/software/gcc/

>Any ideas how to fix this will be greatly appreciated

Every line of this question, perhaps even its concept, is broken somehow.

Your UART may have a transmit function that takes as parameters:

  • a handle - indicating which UART peripheral the data is destined, which I'll ignore below for brevity,
  • a pointer to the data, which must be 32-byte aligned,
  • the length of the data,
  • a timeout, which possibly is needed, or possibly is only needed because the implementation of it and/or the code that calls it is poor.

Combining those in one structure would be good if all the data was fixed at compile time.

But if the data changes at run time, having to construct that structure is wasteful overhead, and a better implementation would to pass at least the the pointer and length as individual parameters.

>How do I declare an array of structs with one element a byte aligned array of uint8_t

This might be the picture.

But seriously consider whether that command structure is sensible or not.

#include <string.h>
#include "cmsis_compiler.h" // for portability, try to abstract compiler extensions as much as possible
#include "FreeRTOS.h" // for the pdMS_TO_TICKS macro
 
// Define a timeout in milliseconds
#define MY_TIMEOUT pdMS_TO_TICKS(50)
 
// Declare a command structure type
typedef struct
{
  uint8_t numBytes;
  uint32_t timeout;
  const uint8_t *cmd; // it is what this points at that must be 32-byte aligned
} myCmdStruct_t;
 
// Define example command buffer and structure that are fixed at compile-time
static const uint8_t myFixedCmd[] __ALIGNED(32) = "*****UART_TwoBoards comm ... ";
static const myCmdStruct_t myFixedCmdStruct = {sizeof(myFixedCmd), MY_TIMEOUT, myFixedCmd};
 
// Define example command buffer and structure that may take any (32-byte aligned) data at run-time
static uint8_t myVariableCmd[100] __ALIGNED(32);
static myCmdStruct_t myVariableCmdStruct;
 
// Declare example UART transmit function
// The const qualifier means the function will not change what cmdStruct points at
// For this example, a zero return indicates it sent successfully
extern int MyUartTxFunction(const myCmdStruct_t *cmdStruct);
 
 
int MyExampleFunction(void)
{
  int result;
 
  // Example sending the fixed data
  result = MyUartTxFunction(&myFixedCmdStruct);
 
  // Example sending some variable data
  if (!result)
  {
    myVariableCmdStruct.timeout = MY_TIMEOUT;
    myVariableCmdStruct.cmd = myVariableCmd;
 
    #define SOME_VARIABLE_DATA_1 "hello"
    // Copy excluding terminating NUL
    // Take care this memcpy does not protect against copying too much and overrunning the buffer
    memcpy(myVariableCmd, SOME_VARIABLE_DATA_1, sizeof(SOME_VARIABLE_DATA_1) - 1);
    myVariableCmdStruct.numBytes = sizeof(SOME_VARIABLE_DATA_1) - 1;
    result = MyUartTxFunction(&myVariableCmdStruct);
  }
 
  // Example sending some more variable data
  if (!result)
  {
      // If the timeout and the buffer are unchanged, they do not need initialising again
      #define SOME_VARIABLE_DATA_2 " world"
      memcpy(myVariableCmd, SOME_VARIABLE_DATA_2, sizeof(SOME_VARIABLE_DATA_2) - 1);
      myVariableCmdStruct.numBytes = sizeof(SOME_VARIABLE_DATA_2) - 1;
      result = MyUartTxFunction(&myVariableCmdStruct);
  }
 
  // Do something if there was an error
  if (result)
  {
 
  }
  
  return result;
}

alister
Lead

A bug in my init

static const myCmdStruct_t myFixedCmdStruct = {sizeof(myFixedCmd) - 1, MY_TIMEOUT, myFixedCmd};

> I took that to mean I could have 1 variable length array in a struct as long as it was the last element in the struct and I defined it later in the program. Is that wrong?

Yes, it is incorrect. You can't have variable-length members of a struct.

> I was thinking I just didn't know how to make the ALIGN_32BYTES macro work with an array of structs with an array as one element of the struct.

Remove the ALIGN_32BYTES macro from it and you'll find you get the same error. You can't assign strings like you can with, say, integers.

> Regardless, I think this is a case of me trying something fancy without knowing enough C++ to pull it off. I'll work on a simpler approach.

I would tend to agree. I don't think you need things aligned to a 32-byte boundary here at all. I'm guessing the example might be using DMA and is trying to avoid cache issues. If your structure is const, you don't need to worry about this at all since it will be stored in flash and never change. But you need to define it all at once rather than doing it later on in the program.

struct CommandStruct {
  uint8_t numBytes;
  uint32_t timeout;
  const char * cmd;
};
 
const CommandStruct commands[3] = {
    {5, 100, "hello"},
    {6, 100, " world"},
    {1, 100, "!"}};

Or just store the strings and use strlen() to get the length.

If you feel a post has answered your question, please click "Accept as Solution".
magene
Senior II

Thanks for all the help - I think I've got enough now to make this work.