Reputation: 487
I am new to C and using it to program a Nordic nrf52 chip. I believe my problem is a general C one though rather than application.
I am setting up an array of structs using macros predefined in the chip SDK. Using those macros in the array initialisation works, but doing element by element does not.
So, the following works:
nrf_twi_mngr_transfer_t transfers_1[2] = { \
NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP), \
NRF_TWI_MNGR_READ (MSBARO5X_0_ADDR , &p_buffer[0], sizeof(p_buffer), 0)
};
Where:
typedef struct {
uint8_t * p_data; ///< Pointer to the buffer holding the data.
uint8_t length; ///< Number of bytes to transfer.
uint8_t operation; ///< Device address combined with transfer direction.
uint8_t flags; ///< Transfer flags (see @ref NRF_TWI_MNGR_NO_STOP).
} nrf_twi_mngr_transfer_t;
NRF_TWI_WRITE and _READ are macros that use further macros, for example:
#define NRF_TWI_MNGR_WRITE(address, p_data, length, flags) \
NRF_TWI_MNGR_TRANSFER(NRF_TWI_MNGR_WRITE_OP(address), p_data, length, flags)
which uses
#define NRF_TWI_MNGR_WRITE_OP(address) (((address) << 1) | 0)
and
#define NRF_TWI_MNGR_TRANSFER(_operation, _p_data, _length, _flags) \
{ \
.p_data = (uint8_t *)(_p_data), \
.length = _length, \
.operation = _operation, \
.flags = _flags \
}
What I want to do is change individual items in this array, for example:
transfers_1[0] = NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
However when I do that, I get the error "expected an expression".
MSBARO5X_0_ADDR is also defined in a define statement: #define MSBARO5X_0_ADDR 0x76
If I replace this in any of the above code with a variable, I get the same "expected an expression" error. I suspect the two problems I have are due to the same lack of understanding on my part. SO forgive me for combining the two in a single post.
So the questions are: -Why am I getting this error? -Is it possible to change individual items in my array, and if so how? -Is it possible to use a variable in place of the MSBARO5X_ADDR, and if so how?
Many thanks!
Upvotes: 1
Views: 3643
Reputation: 132969
If you define the value of a structure the moment you declare it, the compiler will infer the type of the structure from the declaration. So this here will compile:
struct coordinates {
int x;
int y;
};
struct coordinates origin = { 10, 20 }; // This is OK
But if you assign a value to a previously declared variable, the compiler cannot infer its type. This code won't compile:
struct coordinates origin;
origin = { 10, 20 }; // ERROR! The type of the rvalue is unknown!
The type is unknown, because two structures are not equivalent in C just because they have the same members. E.g. this is legal in C:
struct coordinates {
int x;
int y;
};
struct dayOfYear {
int day;
int month;
};
Now what would { 5, 8 }
be? The coordinates (5/8) or the 5th of August? It could be both. All that he compiler knows is that it is a struct of type { int, int }
. Yet this does not define a type in C. The following is possible in some languages but it's not possible in C:
struct dayOfYear date = { 2, 3 };
struct coordinates cords = date; // ERROR!
Despite the fact that both structures are of type { int, int }
, for the compiler struct dayOfYear
and struct coordinates
are two completely distinct and unrelated data types.
If you want to declare a hardcoded struct value, you need to tell the compiler what kind of struct that is:
struct coordinates origin;
origin = (struct coordinates){ 10, 20 }; // This is OK
Your NRF_TWI_MNGR_TRANSFER
defines a hardcoded struct but only when you use that in a definition the compiler knows the type. If you try to use it as an assignment, you need to cast to the correct type.
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
Which is not really a cast, even though it has the same syntax. In fact this is just telling the compiler how to interpret the following data.
Upvotes: 1
Reputation: 170074
Ultimately, the macro expands into a brace enclosed initializer. Such a thing is not an expression, so it cannot be used as the right hand side of plain assignment (assignment and initialization are different things). It will work as part of a larger initializer, but not the way you try to use it unmodified.
But all is not lost. The syntax of the initializer implies c99 support. So we can use a trick. Structure objects can be assigned to eachother. So we need only obtain an object from somewhere. We can use a compound literal in order to create said object:
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(/*Your arguments*/);
Upvotes: 1