A part of the C program that I am writing includes initialization of an input table using sc_memset() function. The table is defined by a typedef struct as shown below.
typedef struct {
UINT32 switchnum;
UINT32 feedback[8];
UINT32 switch_output[8];
} SWITCH_CHECK_IN;
SWITCH_CHECK_IN switch_input_table;
All the table elements, that is switchnum, feedback and switch_output should be initialized to zero.The sc_memset function prototype to be used for initialization is :
extern void sc_memset (volatile unsigned char *dest, unsigned long n, unsigned char data);
I have written the initialization code and because of the type differences in SWITCH_CHECK_IN & volatile unsigned char, I have tried to do some casting as below (I have tried several cast statements) but everytime I get a 'passing arg 1 of sc_memeset from incompatible pointer type' error.
while( *(volatile unsigned char *) &switch_input_table) {
{
sc_memset( &switch_input_table, sizeof(switch_input_table), 0 );
}
I'm new to C so I am not quite sure if my general approach is correct. Kindly,
1. Where am I going wrong? Could you please show me the correct way.
2. What other methods can be used?
Thanks in advance.
You need to cast the pointer to struct into a pointer to unsigned char, just like you do in the while condition:
sc_memset( (unsigned char*)&switch_input_table, ...
You shouldn't need volatile in the cast - the function implicitly adds volatile type qualifier to the passed parameter. Why it has volatile, I have no idea - it's fishy code unless the function expects a hardware register etc as input.
Related
I have a function as follows that processes the information contained in an array of type unsigned char:
unsigned char LRCsimple(unsigned char *p, createLRC , unsigned char length)
{
}
Works great for mostly unsigned char arrays.
Now, I have a signed array and when I use such a function and it works very well, but I have a warning when compiling the code:
> ../src/apptcpipserver.c:102:9: warning: pointer targets in passing argument 1 of 'LRCsimple' differ in signedness [-Wpointer-sign]
if (0x01 == LRCsimple(apptcpipserverData.cRxedData,0x00,(apptcpipserverData.cRxedData[0x02] - 0x02)))
If I want to avoid this warning, I think the optimal solution is to create a function similar to the one above, but for a signed array, as follows:
unsigned char signedLRCsimple(char *p, createLRC , unsigned char length)
{
}
Or is there something else I can do to avoid that warning message?
Strict aliasing rule allows unsigned char and char alias. Therefore you should be able reuse LRCsimple for processing char*.
Therefore signedLRCsimple could be implemented as:
unsigned char signedLRCsimple(char *p, createLRC xxx, unsigned char length)
{
return LRCsimple((unsigned char*)p, xxx, length);
}
To avoid forcing client to change their code to use signedLRCsimple you could use generic selection introduced in C11 in form of _Generic. Typically it is used to select a function pointer basing on the type of first argument of _Generic.
#define LRCsimple(p, xxx, length) \
_Generic((p), unsigned char*: LRCsimple, \
char *: signedLRCsimple)(p, xxx, length)
Whenever LRCsimple is called the generic selection selects between LRCsimple for unsigned char* and signedLRCsimple for char*. For other types an error is raised.
I am writing an at command for a radio module, I am trying to use the following function, however I cannot seem to pass anything for the 2nd argument that the compiler (SDDC) likes.
Function:
radio_receive_packet(uint8_t *length, __xdata uint8_t * __pdata buf)
My code:
static void
at_find(void)
{
__xdata uint8_t mbuf[MAX_PACKET_LENGTH];
// Cycle netID's 1-1000
int i;
for(i=1; i<=1000; i++)
{
param_set(3, i);
param_save();
if (radio_receive_packet(MAX_PACKET_LENGTH, mbuf))
{
printf("Traffic found at %d\n", i);
}
}
at_ok();
}
running this code produces the following error:
radio/at.c:403: error 88: cast of LITERAL value to 'generic'
pointer from type 'const-unsigned-char literal' to type
'unsigned-char generic* fixed'
I've been slamming my head against a wall, I've used C before but not with SDDC or the xdata and pdata types. Also I have never been real strong with pointers and such. Any advice would be appreciated, Another section of the radio code uses this function exactly how I am, only the buffer is declared globally.
As per the function signature
radio_receive_packet(uint8_t *length, __xdata uint8_t * __pdata buf)
the first argument should be a pointer. In your case,
if (radio_receive_packet(MAX_PACKET_LENGTH, mbuf))
it pretty much looks like a MACRO value, maybe of type int or const-unsigned-char literal whatever, but not certainly a uint8_t *.
Hint: __xdata uint8_t mbuf[MAX_PACKET_LENGTH]; Notice the array size.
I'd like to extend #SouravGhosh's answer with a solution: You should define a variable holding the buffer length at the beginning of your at_find() function:
uint8_t buffer_length = MAX_PACKET_LENGTH;
Then you pass a pointer to that variable as first parameter to the radio_receive_packet() function:
if (radio_receive_packet(&buffer_length, mbuf))
{
[...]
}
So your problem seems to be with the first parameter and not the second parameter.
when I had a look on the sources of opensc, especial the libpkcs11.c file, I found a type declaration combined with a function call which I just don't understand:
CK_RV rv, (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) sc_dlsym(mod->handle, "C_GetFunctionList");
I know that:
CK_RV is a typedef for unsigned long
CK_FUNCTION_LIST_PTR_PTR is a typedef for something like **ck_function_list where ck_function_list is a struct
rv is a variable
c_get_function_list is a variable
But if I split the first line and substitute the typedefs with their original values , I get something like:
unsigned long rv;
unsigned long (*c_get_function_list)(**ck_function_list);
So, what does the (**ck_function_list) in the second line mean ?
Thanks in advance,
Robert
unsigned long (*c_get_function_list)(<param>);
is a function pointer to a function whose prototype is.
unsigned long func(<param>);
The pointer here is c_get_function_list
c_get_function_list is pointer to function. When assigned, you can call the pointed function like normal function call: c_get_function_list( param ).
I had this method(simplified):
void addraw(struct chain*a, uint8_t *data).
The point being I could call it from functions like:
void adduint16(struct chain*a, uint16_t val)
{
uint8_t x[2] = {0};
memcpy(x, &val, 2);
addraw(chain, x);
}
Say now if I have method:
void addstr(struct chain*a, char* val)
I could easily do:
void addstr(struct chain*a, char* val)
{
addraw(chain, (uint8_t*) val);
}
But I think it is not always OK to pass char * as uint8_t pointer etc.
So is having the addraw function such prototype better?
void addraw(struct chain*a, void *data)
would I avoid the cast problem? and still use Like I desire? e.g., with ints and strings as I showed above
would [the prototype with void*] avoid the cast problem?
Yes, a prototype with void* will let you avoid casting pointers at the point of call.
[can I] use Like I desire?
This depends on what you want to do: if you plan to interpret the data pointed to by the data pointer as data pointing to unsigned data, and pass signed data instead, you will get implementation-specific behavior. If all you need to do is copying "raw" data from one buffer to another, void* is a perfect choice.
You said,
But I think it is not always OK to pass char * as uint8_t pointer etc.
Short answer: You are right.
Longer answer: Depends on your platform if char on your platform is an unsigned integer value, you should be OK. If not, you are likely to run into problems associated with mixing signed and unsigned integer values.
The problem won't go away by changing the signature of addraw to:
void addraw(struct chain*a, void *data)
It'll appear to go away when you compile a file in which adddraw is used. However, inside adddraw, you have convert data to a pointer of either uint8_t* or char*. At that time, the problem of mixing signed and unsigned integers has to be dealt with.
I am getting an error from my compiler as follow:
C51 COMPILER V9.01 - SN: C1ADC-HAI60D COPYRIGHT KEIL ELEKTRONIK GmbH
1987 - 2009
* WARNING C260 IN LINE 300 OF SEQUENCE.C: '=': pointer truncation
* ERROR C190 IN LINE 301 OF SEQUENCE.C: '&': not an lvalue
The following is my code:
struct myCond{
unsigned char currStatus;
unsigned char prevStatus;
unsigned int *timer;
unsigned char *flag;
}
struct myCond StatCond;
unsigned int data timerdata;
bit bdata timeflag;
void someSubroutine (void)
{
struct myCond *tempCond;
tempCond = &StatCond;
tempCond->timer = &((unsigned int)timerdata);
tempCond->flag = &((unsigned char)timeflag);
}
Are we supposed to guess which line is 301?
The problems, as I understand are here:
tempCond->timer = &((unsigned int)timerdata);
tempCond->flag = &((unsigned char)timeflag);
(unsigned int)timerdata and (unsigned char)timeflag are values, r-values to be precise. They cannot be modified or assigned unlike l-values, which plain timerdata and timeflag are. And so you can't take addresses of r-values with &. It would be the same as, say, writing &1. 1 on its own does not exist as an object in data memory.
You should write instead:
tempCond->timer = &timerdata;
tempCond->flag = (unsigned char*)&timeflag;
And I'm not quite sure that it is legal to take an address of a bit variable. The last line may fail to compile.
Perhaps redefining the structure would help:
struct myCond{
...
bit bdata *flag; // or maybe without bdata
}
and then you'd write tempCond->flag = &timeflag;.
unsigned int data timerdata; // what is 'data', is it defined?
bit bdata timerflag; // what are 'bit' and 'bdata', are they defined?
Check your code with regard to my questions above. Compiler errors are often reported multiple lines after the real offense.