I'm newbie C programmer working on maintaining some legacy embedded C code that looks problematic. In the following snippets I have simplified:
UINT16 adcFunc(UINT8 adc, UINT8 channel)
{
ADC_t* adc_ptr = (ADC_t*)(adc << 4);
ADC_CH_t* adc_ch_ptr;
adc_ch_ptr = (ADC_CH_t*)((UINT8*)&(adc_ptr->CH0) + sizeof(ADC_CH_t) * channel);
...
}
Where the structure definition is given as:
typedef struct ADC_struct
{
...
register8_t reserved_0x1E;
register8_t reserved_0x1F;
ADC_CH_t CH0; /* ADC Channel 0 */
ADC_CH_t CH1; /* ADC Channel 1 */
ADC_CH_t CH2; /* ADC Channel 2 */
ADC_CH_t CH3; /* ADC Channel 3 */
} ADC_t;
With the pointer size being 2 bytes and UINT8 represented as a typedef unsigned char. When linting the code, my linter reports back a warning
cast from UINT8* to ADC_CH_t* increases required alignment from 1 to 2 on the line
adc_ch_ptr = (ADC_CH_t*)((UINT8*)&(adc_ptr->CH0) + sizeof(ADC_CH_t) * channel);
The code is trying to calculate the correct offset into the struct for the channel pointer adc_ch_ptr (where channel is between 0 and 3) It looks like a strict aliasing violation to me and I removed the cast from (UINT8*) senselessly and it crashed the application.
Can anyone shed some light on how to correctly calculate the pointer to the correct channel without aliasing and padding/alignment issues?
Thanks
Avoid this pointer magic, and trust the compiler to understand the switch:
UINT16 adcFunc(UINT8 adc, UINT8 channel)
{
/* this should be hidden inside a macro or an inline function*/
ADC_t *adc_ptr = FIND_BASE_ADDRESS(adc);
ADC_CH_t *adc_ch_ptr;
switch (channel) {
case 0: adc_ch_ptr = &adc_ptr->CH0; break;
case 1: adc_ch_ptr = &adc_ptr->CH1; break;
case 2: adc_ch_ptr = &adc_ptr->CH2; break;
case 3: adc_ch_ptr = &adc_ptr->CH3; break;
/* should not happen ... */
default: return 0xffff;
}
/* do something with adc_ch_ptr ... */
...
return something_usefull_here;
}
Two simple solutions are:
Ignore your “linter”. Leave the code as it is.
Change adc_ch_ptr = (ADC_CH_t*)((UINT8*)&(adc_ptr->CH0) + sizeof(ADC_CH_t) * channel); to adc_ch_ptr = &adc_ptr->CH0 + channel;.
Either of these relies on the address arithmetic working beyond what the C standard requires and the structure not having any weird (and unnecessary) padding. Slightly more complicated solutions using strictly conforming C code are below.
The changed code above simply treats the CH* members as if they were an array of ADC_CH_t; adding an integer channel to a pointer to the first element (with index 0) of an array produces a pointer to another element in the array (with index channel). The original code does the same arithmetic except in units of bytes instead of elements of type ADC_CH_t. It appears unnecessary to use bytes, as the arithmetic with elements should produce the same results. So it is unclear why the original author chose to use bytes, given that the resulting code is more cumbersome.
Two solutions that use strictly conforming C code are:
Use an array (defined here as a compound literal) to look up the desired address:
adc_ch_ptr = (ADC_CH_t *[]) {
&adc_ptr->CH0, &adc_ptr->CH1, &adc_ptr->CH2, &adc_ptr->CH3,
} [channel];
Use a switch:
switch (channel)
{
case 0: adc_ch_ptr = &adc_ptr->CH0; break;
case 1: adc_ch_ptr = &adc_ptr->CH1; break;
case 2: adc_ch_ptr = &adc_ptr->CH2; break;
case 3: adc_ch_ptr = &adc_ptr->CH3; break;
}
Related
I have three diferent vectors with the name of diferents towns inside:
V_NombrePueblos listTown1={"Abrera","Granollers","Cardedeu","Manresa","Martorell"};
V_NombrePueblos listTown2={"Astorga","Benavente","Bembibre","Camarzana","Ferrol"};
V_NombrePueblos listTown3={"Arteijo","Betanzos","Cariño","Cedeira","Cerdido"};
The user tell me the number of vector and the position for print the town. I think in use a function with a switch inside for do this:
typedef char nameList[8];
void returnTown(int listTown, int position){
nameList numList;
if (listTown==0){
strcpy(numList, "listTown1");
}
if (listTown==1){
strcpy(numList, "listTown2");
}
if (listTown==2){
strcpy(numList, "listTown3");
}
switch (position){
case 1:
printf("%s", numList[0]);
break;
case 2:
printf("%s", numList[1]);
break;
case 3:
printf("%s", numList[2]);
break;
case 4:
printf("%s", numList[3]);
break;
case 5:
printf("%s", numList[4]);
break;
But when I try to print example:
returnTown(0,1)
The console doesn't show nothing, with the previus code the console should show "Abrera"
The problem is in the printf insede the switch,
If I put:
printf("%s",listTown1[0] )
The code show "Abrera" fine, but I need pass the name of the vector like a varName, because sometimes will be listTown1, other times listTown2 or listTown3...
Any idea?
Thanks
Copying names of variables doesn't mean refering variables.
To refer variables, you should use pointers.
You will want something like this:
void returnTown(int listTown, int position){
V_NombrePueblos* numList;
switch (listTown){
case 0: numList = &listTown1; break;
case 1: numList = &listTown2; break;
case 2: numList = &listTown3; break;
default: return;
}
if (1 <= position && position <= 5){
printf("%s", (*numList)[position - 1]);
(rest part of this function isn't shown because I respect the original code snippet)
What you are trying to do won't work in C - you can't build variable names dynamically like that.
Any time you find yourself defining a bunch of variables with the same type and with ordinal names (var1, var2, etc.), that's a real strong hint you want to use an array. In this case, you could do something like
/**
* I am *assuming* that vNombrePueblos is a typedef name for char *[5],
* based on the declarations in your code.
*
* The size of the listTowns array is taken from the number of initializers;
* in this case, 3.
*/
vNombrePueblos listTowns[] = {
{"Abrera","Granollers","Cardedeu","Manresa","Martorell"},
{"Astorga","Benavente","Bembibre","Camarzana","Ferrol"},
{"Arteijo","Betanzos","Cariño","Cedeira","Cerdido"}
};
This way instead of trying to figure out which listTownN variable you want, you just index into this array. To print out the correct town, all you need is the two indices:
/**
* You need to pass the list of towns as an argument to your function;
* since arrays lose their "array-ness" under most circumstances, you also
* have to pass the array size to make sure you don't try to access something
* past the end of it.
*/
void returnTown( vNombrePueblos listTowns[], int numTowns, int town, int position )
{
if ( town < numTowns )
printf( "%s\n", listTowns[town][position] );
else
fprintf( stderr, "No such entry\n" );
}
You'll need to keep track of the number of entries in listTowns yourself - arrays in C don't carry any metadata about their size, and under most circumstances (such as when you pass it as an argument to a function) an expression of type "array of T" will "decay" into an expression of type "pointer to T", so the sizeof arr / sizeof arr[0] trick won't work to get the number of elements.
I am trying to convert char array to unsigned short but its not working as it should.
char szASCbuf[64] = "123456789123456789123456789";
int StoreToFlash(char szASCbuf[], int StartAddress)
{
int iCtr;
int ErrorCode = 0;
int address = StartAddress;
unsigned short *us_Buf = (unsigned short*)szASCbuf;
// Write to flash
for(iCtr=0;iCtr<28;iCtr++)
{
ErrorCode = Flash_Write(address++, us_Buf[iCtr]);
if((ErrorCode &0x45)!= 0)
{
Flash_ClearError();
}
}
return ErrorCode;
}
When I see the Conversion, on us_Buf[0] I have value 12594, us_Buf[1]= 13108 like that and I have values only uptous_Buf[5]` after that it is "0" all remaining address.
I have tried to declare char array like this also
char szASCbuf[64] = {'1','2','3','4','5','6','7','8','9','1',.....'\0'};
I am passing the parameters to function like this
StoreToFlash(szASCbuf, FlashPointer); //Flashpointe=0
I am using IAR embedded workbench for ARM. Big enedian 32.
Any suggestions where i am doing wrong?
Thanks in advance.
Reinterpreting the char array szASCbuf as an array of short is not safe because of alignment issues. The char type has the least strict alignment requirements and short is usually stricter. This means that szAscBuf might start at address 13, whereas a short should start at either 12 or 14.
This also violates the strict aliasing rule, since szAscBuf and us_Buf are pointing at the same location while having different pointer types. The compiler might perform optimisations which don't take this into account and this could manifest in some very nasty bugs.
The correct way to write this code is to iterate over the original szASCBuf with a step of 2 and then do some bit-twiddling to produce a 2-byte value out of it:
for (size_t i = 0; i < sizeof(szAscbuf); i += 2) {
uint16_t value = (szAscbuf[i] << 8) | szAscbuf[i + 1];
ErrorCode = Flash_Write(address++, value);
if (ErrorCode & 0x45) {
Flash_ClearError();
}
}
If you really intended to treat the digit characters with their numeric value, this will do it:
uint16_t value = (szAscbuf[i] - '0') + (szAscbuf[i + 1] - '0');
In case you just want the numeric value of each character in a 2-byte value (1, 2, 3, 4, ...), iterate over the array with a step of 1 and fetch it this way:
uint16_t value = szAscbuf[i] - '0';
That's normal !
Your char array is "123456789123456789123456789" or {'1','2','3','4','5','6','7','8','9','1',.....'\0'}
But in ASCII '1' is 0x31, so when you read the array as a short * on a big endian architecture, it gives :
{ 0x3132, 0x3334, ... }
say differently in decimal :
{ 12594, 13108, ... }
I'm trying to interpret WebSocket Frames that I get over a TCP connection. I want to do this in pure C (so no reinterpret_cast). The Format is specified in IEEE RFC 6455. I want to fill the following struct:
typedef struct {
uint8_t flags;
uint8_t opcode;
uint8_t isMasked;
uint64_t payloadLength;
uint32_t maskingKey;
char* payloadData;
} WSFrame;
with the following Function:
static void parseWsFrame(char *data, WSFrame *frame) {
frame->flags = (*data) & FLAGS_MASK;
frame->opcode = (*data) & OPCODE_MASK;
//next byte
data += 1;
frame->isMasked = (*data) & IS_MASKED;
frame->payloadLength = (*data) & PAYLOAD_MASK;
//next byte
data += 1;
if (frame->payloadLength == 126) {
frame->payloadLength = *((uint16_t *)data);
data += 2;
} else if (frame->payloadLength == 127) {
frame->payloadLength = *((uint64_t *)data);
data += 8;
}
if (frame->isMasked) {
frame->maskingKey = *((uint32_t *)data);
data += 4;
}else{
//still need to initialize it to shut up the compiler
frame->maskingKey = 0;
}
frame->payloadData = data;
}
The code is for the ESP8266, so debugging is only possible with printfs to the serial console. Using this method, I discovered that the code crashes right after the frame->maskingKey = *((uint32_t *)data); and the first two ifs get skipped, so this is the first time I cast a pointer to another pointer.
The data is not \0 terminated, but i get the size in the data received callback. In my test, I'm trying to send the message 'test' over the already established WebSocket, and the received data length is 10, so:
1 byte flags and opcode
1 byte masked and payload length
4 bytes masking key
4 bytes payload length
At the point the code crashes, I expect data to be offsetted by 2 bytes from the initial position, so it has enough data to read the following 4 bytes.
I did not code any C for a long time, so I expect only a small error in my code.
PS.: I've seen a lot code where they interpret the values byte-by-byte and shift the values, but I see no reason why this method should not work either.
The problem with casting a char* to a pointer to a larger type is that some architectures do not allow unaligned reads.
That is, for example, if you try to read a uint32_t through a pointer, then the value of the pointer itself has to be a multiple of 4. Otherwise, on some architectures, you will get a bus fault (e.g. - signal, trap, exception, etc.) of some sort.
Because this data is coming in over TCP and the format of the stream / protocol is laid out without any padding, then you will likely need to read it out from the buffer into local variables byte by byte (e.g. - using memcpy) as appropriate. For example:
if (frame->isMasked) {
mempcy(&frame->maskingKey, data, 4);
data += 4;
// TODO: handle endianness: e.g.: frame->maskingKey = ntohl(frame->maskingKey);
}else{
//still need to initialize it to shut up the compiler
frame->maskingKey = 0;
}
There's two problems:
data might not be correctly aligned for uint32_t
The bytes in data might not be in the same order as your hardware uses for value representation of integer. (sometimes called "endianness issue").
To write reliable code, look at the message specification to see which order the bytes are coming in. If they are most-significant-byte first then the portable version of your code would be:
unsigned char *udata = (unsigned char *)data;
frame->maskingKey = udata[0] * 0x1000000ul
+ udata[1] * 0x10000ul
+ udata[2] * 0x100ul
+ udata[3];
This might look like a handful at first, but you could make an inline function that takes a pointer as argument, and returns the uint32_t, which will keep your code readable.
Similar problem applies to your reads of uint16_t.
I use a struct of bit fields to access each colour channel in a pixel, the problem is that quite often I have code that applies in the same way to each channel, but because I cannot just iterate over the members of a struct in C I end up having 3 copies of the same code for each member, or more inconveniently have to use switch-case statements.
I figured it would be more elegant if I could use a macro so that I can access a member by providing a number, ideally a macro that would make .CHAN(i) become either .r, .g or .b depending on whether the integer variable i contains a 0, 1 or 2. Except I have no idea how one would make such a macro or even if that's possible.
A detail but each member is something like 12 bits, not 8 as one might expect, so I cannot just turn it into an array or have a union with a pointer. Also X-Macros won't do as I often need to do many things to each channel before doing the same to another channel, in other words the for loop for going through each member can contain a lot more than just one line.
EDIT: Here's some code, first the struct:
typedef struct
{
uint32_t b:12;
uint32_t g:12;
uint32_t r:12;
uint32_t a:12;
} lrgb_t;
Now an example of what my problem looks like in code:
for (ic=0; ic<3; ic++)
{
for (i=0; i<curvecount; i++)
{
curve[i].p0.x = (double) i;
curve[i].p3.x = (double) i+1.;
switch (ic) // this is what I'm trying to eliminate
{
case 0:
curve[i].p0.y = pancol[i].r / 4095.;
curve[i].p3.y = pancol[i+1].r / 4095.;
break;
case 1:
curve[i].p0.y = pancol[i].g / 4095.;
curve[i].p3.y = pancol[i+1].g / 4095.;
break;
case 2:
curve[i].p0.y = pancol[i].b / 4095.;
curve[i].p3.y = pancol[i+1].b / 4095.;
break;
}
// Ideally this would be replaced by something like this, CHAN() being an hypothetical macro
// curve[i].p0.y = pancol[i].CHAN(ic) / 4095.;
// curve[i].p3.y = pancol[i+1].CHAN(ic) / 4095.;
}
... // more stuff that ultimately results in a bunch of pixels being written, channel after channel
}
as pointed out in the comments, this doesn't really address the OP's problem because the members on his struct are bitfields that wouldn't align with an array. I'll keep the answer here though, in hopes it can still be useful to someone.
I think a union is what you want.
You can write your struct such as
union
{
struct
{
float r;
float g;
float b;
}rgb;
float channel[3];
} color;
This way the struct will be in the same place in memory as the float[3], and you can effectively access the same members as either a struct member or as an element in the array.
You might have to look up the exact syntax, but you get the idea.
One possibility might be to wrap the repeated code into a function, and then call it for each of the channels:
typedef struct {
int r:12;
int g:12;
int b:12;
} Pixel;
int inc(int val) {
return val + 1;
}
int main(void) {
Pixel p = {0, 0, 0};
p.r = inc(p.r);
p.g = inc(p.g);
p.b = inc(p.b);
return 0;
}
After reading the code that you added I made some changes to my suggested macro
#define CHAN(ic) \
(ic == 1) ? curve[i].p0.y = pancol[i].r / 4095; curve[i].p3.y = pancol[i+1].r / 4095; : \
(ic == 2) ? curve[i].p0.y = pancol[i].g / 4095; curve[i].p3.y = pancol[i+1].g / 4095; : \
curve[i].p0.y = pancol[i].b / 4095; curve[i].p3.y = pancol[i+1].b / 4095;
The macro CHAN(ic) will evaluate 'ic' in order to decided which member to manipulate. If 'ic' is 1 then the member '.r' will be manipulated if 'ic' is 2 then '.g' will be manipulated, and if 'ic' is neither 1 or 2 then '.b' will be manipulated because of this assumption you must make sure that 'ic' is properly set otherwise you could screw with the value of panco[i].b and pancol[i+1].b . You code should look something like the following but you will most likely need to tweak the macro a bit let me know if you have any questions.
//#define CHAN(ic) here
for (ic=0; ic<3; ic++)
{
for (i=0; i<curvecount; i++)
{
curve[i].p0.x = (double) i;
curve[i].p3.x = (double) i+1.;
CHAN(ic)
}
... // more stuff that ultimately results in a bunch of pixels being written, channel after channel
}
Also please note that my macro will do exactly the same thing as your switch case. The only difference is that it is defined in a macro the point I am trying to make is that the difference between the switch case and the macro is purely visual.
I am trying to iterate through an array that will contain up to a maximum of 4 elements - no other knowledge of the array-length exists.
Pseudo Code
void insert_vals(uint8_t num, uint8_t *match_num, uint8_t *value)
{
uint8_t i;
while(data_exists) // how do I determine if data exists in 'value'?
{
switch(num)
{
case 0:
{
switch(match_num[i])
{
case 0:
hw0reg0 = value[i];
case 1:
hw0reg1 = value[i];
case 2:
hw0reg2 = value[i];
case 3:
hw0reg3 = value[i];
}
}
case 1:
{
switch(match_num[i])
{
case 0:
hw1reg0 = value[i];
case 1:
hw1reg1 = value[i];
case 2:
hw1reg2 = value[i];
case 3:
hw1reg3 = value[i];
}
}
// etc. 2 other cases
}
i++;
}
}
Calling Example (Pseudo Code)
/*
* num: hardware device select from 1 - 4
* match_num: 4 possible matches for each hardware device
* value: 32-bit values to be assigned to 4 possible matches
* NOTE: This function assumes hardware devices are selected
* in a consecutive order; I will change this later.
*/
// example calling code - we could have configured 4 hardware devices
insert_vals(0, [0, 1], [0x00000001, 0x000000FF]); // arg2 and arg3 equal in length
How can I accomplish this?
In a character array, C will automatically add '\0' to the end of the array, but this does not seem to be the case for an integer array. If I was somehow able to determine the length of match_num and value (see if statement) at runtime originally, then that would allow me to create a for loop.
Edit
Since I know that there will be a maximum of 4 elements, couldn't I do something similar to the following?
void insert_vals(uint8_t num, uint8_t *match_num, uint32_t *value)
{
int i;
for(i = 0; i < 4; i++)
{
if(value[i] == -1)
break;
else
{
// Assign data
}
}
}
You can't get the length of an array pointed to given only the pointer. Either you have to pass the length, or it must be constant (always 4) with some sentinel value in the unused elements -- a value that is somehow invalid for your computations (like NUL is for strings).
Is there a value you can guarantee it's not in the "usable" data? (e.g. 0 is no valid character for character strings, therefore Mr. Kernighan and Mr. Ritchie decided to pick it as a "end of array" marker. You could do the same with any value.
Say you know your integer values are between 0 to 512, so you could initialize the whole array e.g. to 1024, then fill it and iterate through it until a number >512 occurs (which has to be your end of array marker).
Another possibility is to pass the number of elements in the array along with the array.