The code demo below works but I’m not sure it’s syntactically correct.
For example, should this
X = *((QWORD*)(pRegCtx->X));
be replaced with
X = *(QWORD*)(pRegCtx->X);
Plus code looks odd using a QWORD cast
RegisterContext RegCtx = { (QWORD)&X };
Without the (QWORD) cast, the linux c compiler reports:
warning: initialization of ‘long unsigned int’ from ‘QWORD *’ {aka
‘long unsigned int *’} makes integer from pointer without a cast
[-Wint-conversion]
Any tips on how make it conform better to the C89 standard?
https://www.onlinegdb.com/0pBta5XO2
#include <stdio.h>
#include <stdint.h>
typedef uint64_t QWORD;
typedef uint32_t DWORD;
typedef uint16_t WORD;
typedef uint8_t BYTE;
typedef struct RegisterContext
{
QWORD X;
} RegisterContext, *PREGISTERCONTEXT;
void MyFun(PREGISTERCONTEXT pRegCtx)
{
QWORD X = 0;
X = *((QWORD*)(pRegCtx->X));
X += 42;
*((QWORD*)(pRegCtx->X)) = X;
}
int main(void)
{
QWORD X = 0;
RegisterContext RegCtx = { (QWORD)&X };
MyFun(&RegCtx);
// Answer to the Ultimate Question of Life, the Universe, and Everything
printf("X=%lu\n",X);
return 0;
}
>Solution :
- Never hide pointers and arrays behind typedefs.
- Use standard int types instead of QWORD and similar. There is no reason to introduce new strange types.
- Use correct printf formats.
- Do not overcomplicate simple things.
typedef struct RegisterContext
{
uint64_t X;
} RegisterContext;
void MyFun(RegisterContext *pRegCtx)
{
uint64_t X = 0;
X = pRegCtx->X;
X += 42;
pRegCtx->X = X;
}
int main(void)
{
uint64_t X = 0;
RegisterContext RegCtx = { X };
MyFun(&RegCtx);
X = RegCtx.X;
printf("X=%"PRIu64"\n", RegCtx.X);
return 0;
}
https://godbolt.org/z/noPW46W3r
If your structure represents the layout of the hardware register mapped into the address space then you need to use macros.
typedef struct RegisterContext
{
uint64_t X;
uint64_t Y;
uint64_t Z;
uint64_t W;
} RegisterContext;
#define REG1ADDRESS 0x40000340
#define REG1 ((volatile RegisterContext*)REG1ADDRESS)
void setX(void)
{
REG1 -> Z = 0x45654564;
}