Initializing pointer member within structure - c

I'm trying to write a module that will read a specific address value from a micro controller, the initialization code has compiled on its own but when I try to compile it within a structure it seem to complain. Are there restriction on initializing pointers within a structure?
#include <stdio.h>
#include <esper.h>
#include <stdlib.h>
#include <stdint.h>
#include "lmk04800.h"
#define NUM_MSS_GPIO 32
#define SEL_NIM 3
#define SOURCE_SEL 4
#define SEL_EXT 5
#define CLK0_3_EN 6
#define CLK4_7_EN 7
#define CLK8_11_EN 8
#define CLK12_15_EN 9
#define CLK16_19_EN 10
#define CLK20_23_EN 11
#define LMK_SYNC 12
typedef struct {
int fd_gpio[NUM_MSS_GPIO];
uint8_t data_gpio[NUM_MSS_GPIO];
uint32_t esata_freqCounter;
uint32_t ext_freqCounter;
uint32_t esata_trgCounter;
uint32_t ext_trgCounter;
tLMK04800 settings;
volatile uint32_t *freqCounter_addr;
volatile uint32_t *trgCounter_addr;
volatile uint32_t *manSync_addr;
freqCounter_addr = (volatile uint32_t *)0x30000000;
trgCounter_addr = (volatile uint32_t *)0x30000100;
manSync_addr = (volatile uint32_t *)0x30000200;
} tESPERModuleTest;
The compilation error I get is:
test/mod_test.h:32: error: expected specifier-qualifier-list before 'freqCounter_addr'

You can't define initial values for struct members when you define the type. It could be useful if it were permitted, and the initial values would be applied automatically to any objects of the type. C just doesn't permit it.
You can only initialize objects.
You've defined a type named tESPERModuleTest. If you want to define and initialize an object of that type, you can do something like this after defining the type (untested code):
tESPERModuleTest obj = {
.freqCounter_addr = (volatile uint32_t *)0x30000000,
.trgCounter_addr = (volatile uint32_t *)0x30000100,
.manSync_addr = (volatile uint32_t *)0x30000200
};
(The other members will be default zero-initialized, or you can provide values for them.)

Related

About the data alignment in c [duplicate]

This question already has answers here:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?
(13 answers)
Closed 1 year ago.
And I define a struct :
#include <stdint.h>
#include <stdio.h>
#define O(type, field) (size_t)(&(((type *)0)->field))
struct byname {
int16_t int16;
int32_t int32;
int64_t int64;};
Then I use sizeof(struct byname) and it return 16 which I can understand.
However when I define the like adding a int8_t:
#include <stdint.h>
#include <stdio.h>
#define O(type, field) (size_t)(&(((type *)0)->field))
struct byname {
int16_t int16;
int32_t int32;
int64_t int64;
int8_t int8;};
It just return 24, I think a int8 only takes 1 by and there are 3 bys padding according to data alignment, so I think the answer should be 20.
Anyone can kindly explain to me how the 24 comes?
The structure contains int64_t. If the compiler thinks that int64_t should be aligned to 8-byte boundary, it is reasonable to make the size of the structure multiple of 8 (therefore 24 bytes instead of 20) to align every int64_t int64; in an array of struct byname to 8-byte boundary.

Declare arrays with different sizes in a C typedef struct

I know how to dynamic allocate a new array with malloc.
I wonder if there's a way to avoid that in this situation:
#define RX_BUFFER_SIZE 256
#define TX_BUFFER_SIZE 128
typedef struct MyBuffer
{
volatile uint8_t RX[RX_BUFFER_SIZE];
volatile uint8_t TX[TX_BUFFER_SIZE];
volatile uint16_t RX_Head;
volatile uint16_t RX_Tail;
volatile uint16_t TX_Head;
volatile uint16_t TX_Tail;
} MyBuffer_t;
typedef struct MyChannel
{
// other stuff
MyBuffer_t buffer;
} MyChannel_t;
then in my code I create several variables like this:
MyChannel_t ch1;
MyChannel_t ch2;
MyChannel_t ch3;
but I would like to set a different sizes of the arrays for each variable. It's ok to select among a small set, i.e.:
#define RX_BUFFER_SIZE_S 32
#define TX_BUFFER_SIZE_S 16
#define RX_BUFFER_SIZE_M 128
#define TX_BUFFER_SIZE_M 64
#define RX_BUFFER_SIZE_L 256
#define TX_BUFFER_SIZE_L 128
Is there a way to achieve this without using malloc?
Declare your buffers as pointers:
typedef struct MyBuffer
{
volatile uint8_t * RX;
volatile uint8_t * TX;
size_t rxSize;
size_t txSize;
volatile uint16_t RX_Head;
...
And then use separate static allocation for the buffers, and use them to initialize your object.
volatile uint8_t ch1_rx_buffer[RX_BUFFER_SIZE_S];
volatile uint8_t ch1_tx_buffer[TX_BUFFER_SIZE_S];
MyChannel_t ch1 = {
.buffer = {
ch1_rx_buffer,
ch1_tx_buffer,
sizeof ch1_rx_buffer,
sizeof ch1_tx_buffer,
...
}
}

BYTE, WORD and DWORD macros definition

I am trying to understand, what would be the best way to define BYTE, WORD and DWORD macros, which are mentioned in answers of this question.
#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
Would it be correct to assume, that:
BYTE is macro defined as
#define BYTE __uint8_t
WORD is macro defined as
#define WORD __uint16_t
DWORD is macro defined as
#define DWORD __uint32_t
If yes, why cast to another macro instead of casting to __uint8_t, __uint16_t or __uint32_t? Is it written like that to increase clarity?
I also found another question which answers include typedef, with little bit more of research I've found answers to question about comparing #define and typedef. Would typedef be better to use in this case?
This is a portable solution:
#include <stdint.h>
typedef uint32_t DWORD; // DWORD = unsigned 32 bit value
typedef uint16_t WORD; // WORD = unsigned 16 bit value
typedef uint8_t BYTE; // BYTE = unsigned 8 bit value
You have it defined at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx, and that is already defined in Windows Data Type headers for WinAPI:
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
and it is a type, and not a macro.

C99 define values passed as literal initializer values to structure, failing as non-const

In the (old) Linux source code (written in C89), a #define occurs that is used as a literal in the initialization of a structure (ide_pci_device_s) using the standard C89 struct literal initializer syntax, however, when I compile with a compiler that supports C99, I get the error initializer element is not constant, below is a sample of the code I am working with which throws the error.
#define ON_BOARD 1
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
#define DEVID_PIIXa ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0})
typedef char byte;
typedef struct ide_pci_devid_t {
int one, two;
} ide_pci_devid_t;
typedef struct ide_hwif_t {
int whatever;
} ide_hwif_t;
typedef struct ide_pci_enablebit_s {
byte reg; /* byte pci reg holding the enable-bit */
byte mask; /* mask to isolate the enable-bit */
byte val; /* value of masked reg when "enabled" */
} ide_pci_enablebit_t;
typedef struct ide_pci_device_s {
ide_pci_devid_t devid;
const char *name;
void (*init_hwif)(ide_hwif_t *hwif);
ide_pci_enablebit_t enablebits[2];
byte bootable;
unsigned int extra;
} ide_pci_device_t;
static ide_pci_device_t ide_pci_chipsets[] = {
// HERE is where it says 'non-const initializer
{DEVID_PIIXa, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
};
How can I still use the value of the #define while minimally altering the structure of the source to build with a C99 compiler?
The problem is the cast in:
#define DEVID_PIIXa ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0})
Your compiler thinks that makes it non-constant. Since where you're using the initializer is initializing a nested ide_pci_devid_t struct, you don't need the cast. Changing that define to:
#define DEVID_PIIXa {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0}
will fix it.
(Lifted to an answer from the comment discussion.)

Tips on redefining a register bitfield in C

I am struggling trying to come up with a clean way to redefine some register bitfields to be usable on a chip I am working with.
For example, this is what one of the CAN configuration registers is defined as:
extern volatile near unsigned char BRGCON1;
extern volatile near struct {
unsigned BRP0:1;
unsigned BRP1:1;
unsigned BRP2:1;
unsigned BRP3:1;
unsigned BRP4:1;
unsigned BRP5:1;
unsigned SJW0:1;
unsigned SJW1:1;
} BRGCON1bits;
Neither of these definitions is all that helpful, as I need to assign the BRP and SJW like the following:
struct
{
unsigned BRP:6;
unsigned SJW:2;
} GoodBRGbits;
Here are two attempts that I have made:
Attempt #1:
union
{
byte Value;
struct
{
unsigned Prescaler:6;
unsigned SynchronizedJumpWidth:2;
};
} BaudRateConfig1 = {NULL};
BaudRateConfig1.Prescaler = 5;
BRGCON1 = BaudRateConfig1.Value;
Attempt #2:
static volatile near struct
{
unsigned Prescaler:6;
unsigned SynchronizedJumpWidth:2;
} *BaudRateConfig1 = (volatile near void*)&BRGCON1;
BaudRateConfig1->Prescaler = 5;
Are there any "cleaner" ways to accomplish what I am trying to do? Also I am slightly annoyed about the volatile near casting in Attempt #2. Is it necessary to specify a variable is near?
Personally, I try to avoid using using bit fields for portability reasons. Instead, I tend to use bit masks so that I can explicitly control which bits are used.
For example (assuming the bit order is correct) ...
#define BRP0 0x80
#define BRP1 0x40
#define BRP2 0x20
#define BRP3 0x10
#define BRP4 0x08
#define BRP5 0x04
#define SJW0 0x02
#define SJW1 0x01
Masks can then be generated as appropriate and values assigned or read or tested. Better names for the macros can be picked by you.
Hope this helps.
I suggest that you dont mix up the bitfield declaration with the adressing of the hardware register.
Your union/struct declares how the bitfields are arranged, then you specify addressing and access restrictions when declaring a pointer to such a structure.
// foo.h
// Declare struct, declare pointer to hw reg
struct com_setup_t {
unsigned BRP:6;
unsigned SJW:2;
};
extern volatile near struct com_setup_t *BaudRateConfig1;
// foo.c
// Initialise pointer
volatile near struct com_setup_t *BaudRateConfig1 =
(volatile near struct com_setup_t *)0xfff...;
// access hw reg
foo() {
...
BaudRateConfig1->BRP = 3;
...
}
Regarding near/far I assume that the default is near unless far is specified, unless you can set the default pointer size to far using compiler switches.

Resources