what is the meaning of (unsigned char*)&ch in the following function call ?
HAL_UART_Transmit(&UartHandle, (unsigned char *)&ch, 1, 0xFFFF);
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, unsigned char *pData, int Size, long Timeout)
{
/*...........Function Body ........*/
}
&ch is an address of some variable, type is unknown given this code. (unsigned int*)&ch is simply casting the result of this expression to a pointer to int.
It takes the address of the variable ch using the address-of operator &. The resulting address is then converted (cast) to the type unsigned int *, i.e. a pointer to an unsigned int. This only makes sense if
The type of ch was not unsigned int to begin with
The size of ch is at least as large as the size of unsigned int
The called function accepts an unsigned int * argument
Since we can see that the type of the argument is in fact uint8_t *, this is very likely a bug. The cast should either be removed (if ch is of type uint8_t already, which it should be) or changed to uint8_t *. Also, the function's parameter should be const, a transmit function shouln't change its argument.
Let's say you have a function that takes an argument of type unsigned int *.
You have an object of type int and you want to pass a pointer to this object the function.
int ch = 42;
Then &ch get you an int * to the int object. You cannot pass &ch directly to your function as &ch is of type int * but the function wants a unsigned int *, so you convert it to unsigned int * with a cast:
(unsigned int *) &ch
Related
I was trying to pass an array to a method. I tried following ways:
func2(ARRAY_NAME, length) => WORKS, no warning
func2(&ARRAY_NAME[0], length) => WORKS, no warning
func2(&ARRAY_NAME, length) => WORKS, but WITH WARNING
I dont understand why the last one (#3) gives warning. &ARRAY_NAME works without warnings in memset, memcpy etc. Why its a problem in custom method?
WARNING message:
functionTest.c:35:11: warning: passing argument 1 of ‘func2’ from incompatible pointer type [-Wincompatible-pointer-types]
35 | func2(&temp, ARRAY_SIZE);
| ^~~~~
| |
| unsigned char (*)[200]
functionTest.c:8:27: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[200]’
8 | void func2(unsigned char* buf, int length)
CODE
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define ARRAY_SIZE 200
void func2(unsigned char* buf, int length)
{
// Change data of any index
buf[0] = 100;
buf[10] = 200;
}
void func1()
{
unsigned char temp[ARRAY_SIZE];
// Initialize
memset(temp, 0, sizeof(temp));
for(int i = 0; i < ARRAY_SIZE; i++)
{
printf("\t%d", temp[i]);
}
printf("\n-----------------------------------------------\n");
printf("Address : %p\n", &temp);
printf("Address of 0th index : %p\n", &temp[0]);
printf("\n-----------------------------------------------\n");
// Pass array in func2
func2(&temp, ARRAY_SIZE); // WARNING
func2(&temp[0], ARRAY_SIZE); // NO WARNING
for(int i = 0; i < ARRAY_SIZE; i++)
{
printf("\t%d", temp[i]);
}
printf("\n-----------------------------------------------\n");
}
int main()
{
func1();
return 0;
}
As it is clear written in the error message
functionTest.c:8:27: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[200]’
8 | void func2(unsigned char* buf, int length)
the function expects a pointer of the type unsigned char * but the argument expression &temp has the type unsigned char ( * )[200] and there is no implicit conversion from one pointer type to another though values of the pointers are the same: the address of the extent of memory occupied by the array.
As for the functions memset and memcpy then they deal with pointers of the type void *. For example the function memset has the following declaration
void *memset(void *s, int c, size_t n);
And a pointer to object of other type can be implicitly converted to pointer of the type void *.
From the C Standard (6.3.2.3 Pointers)
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
func2 is declared to have a first parameter of type unsigned char *, so it should be passed a pointer to a type compatible with unsigned char or a pointer to void, which will be automatically converted to unsigned char *.
With func2(temp, ARRAY_SIZE), the array temp is automatically converted to a pointer to its first element. This pointer is an unsigned char *, so it satisfies the requirements.
With func2(&temp[0], ARRAY_SIZE), temp[0] is an unsigned char, so &temp[0] is a pointer to an unsigned char. This satisfies the requirements.
With func2(&temp, ARRAY_SIZE), &temp is a pointer to an array of 200 elements of unsigned char. It points to the same place as &temp[0], bit its type is different. It is a pointer to an array, not a pointer to unsigned char or to a compatible type nor a pointer to void. So it does not satisfy the requirements, and the compiler complains.
Pointers to unsigned char and pointers to arrays are different. If the type of pu is unsigned char * and the type of pa is unsigned char (*)[200] (a pointer to an array of 200 unsigned char), then adding 1 to pu, as in pu + 1, produces a pointer to the next unsigned char after pu, but adding 1 to pa produces a pointer to the next array after pa. In other words, pu + 1 points to the next byte in memory, but pa + 1 points 200 bytes further along in memory.
One purpose of C’s type system is to help avoid errors. When a non-matching type is passed to a function, the programmer may be expected some behavior other than what the language defines. So the compiler issues a diagnostic message.
With memset, its first parameter is declared to be void *. void is an incomplete type; it acts as a placeholder for other types. memset is designed to work on the bytes of any object, so it accepts a pointer to any object type. When any pointer to an object type is passed for a void * parameter, it is automatically converted to void *, without any diagnostic message.
This is my function:
void eeprom_read_page(unsigned int address, unsigned char lengh, unsigned char *data[40])
{
//unsigned char data[lengh] , i;
unsigned char i;
i2c_start();
i2c_write(EEPROM_BUS_ADDRESS_W);
i2c_write(address>>8); //high byte address
i2c_write(address*0xff); //low byte address
i2c_start();
i2c_write(EEPROM_BUS_ADDRESS_R);
for(i=0 ; i<(lengh-1) ; i++)
{
*data[i+4]=i2c_read(1);
}
*data[lengh+3]=i2c_read(0);
i2c_stop();
}
And this is how I use it somewhere in my code:
eeprom_read_page( ( (rx_buffer1[1]*256)+rx_buffer1[2] ) , rx_buffer1[3] , &tx_buffer1 );
And this is my array define:
#define RX_BUFFER_SIZE1 40
char rx_buffer1[RX_BUFFER_SIZE1],tx_buffer1[RX_BUFFER_SIZE1];
but tx_buffer1 doesn't get values I give in data[]. I want to change tx_buffer1 but don't use return. Any help?
The array declared the following way
#define RX_BUFFER_SIZE1 40
char rx_buffer1[RX_BUFFER_SIZE1],tx_buffer1[RX_BUFFER_SIZE1];
used in the expression
&tx_buffer1
makes the expression type char ( * )[RX_BUFFER_SIZE1].
At the same time the corresponding function parameter
unsigned char *data[40]
has the type unsigned char ** because the compiler implicitly adjusts a parameter having an array type to pointer to an object of the element type of the array.
And moreover the function parameter uses the specifier unsigned char while the array declared with the specifier char.
So the function call is invalid. There is no implicit conversion between the pointer types.
There is no any sense to pass the array to a function by reference because in any case arrays are non-modifiable lvalues.
If you want to pass the array by reference to know its size in the function then the function parameter shall be declared like
char ( *data )[40]
I am getting the following warning whenever the function initSetArray() is called :
error: conversion to ‘long unsigned int’ from ‘int’ may change the sign of the result [-Werror=sign-conversion]
setarray = (set*)malloc(sizeof(set) * number_of_sets);
The function initSetArray simply initializes the setarray.
void initSetArray(set *setarray, int number_of_sets, int number_of_blocks)
{
setarray = (set*)malloc(sizeof(set) * number_of_sets);
}
I have defined two structures which are used in the helper function defined above:
typedef struct{
uint64_t tag; // For identifying the block
uint8_t valid; // Valid bit for the block
uint8_t dirty; // Dirty bit for the block
} block;
typedef struct{
uint64_t index; // For identifying the set
block* way;
} set;
I cannot exactly find out which variable is of type "long unsigned int". What can I do to resolve this issue?
In this statement
setarray = (set*)malloc(sizeof(set) * number_of_sets);
the variable number_of_sets is an integer (int), and because it is used in an expression with sizeof (size_t), the value is converted to match.
size_t is usually an unsigned long. If you don't like the warning, this would fix it:
setarray = (set*)malloc(sizeof(set) * (size_t) number_of_sets);
The malloc function takes a size_t argument, and size_t is defined for your build as unsigned long int (as it frequently is). In your call:
setarray = (set*)malloc(sizeof(set) * number_of_sets);
you are multiplying such a size_t value (the sizeof operator gives a size_t) by a (signed) int variable - hence the warning.
To avoid this, either explicitly cast number_of_sets to a size_t, like this:
setarray = (set*)malloc(sizeof(set) * (size_t)number_of_sets);
Or, better, change the type of that argument to a size_t:
void initSetArray(set *setarray, size_t number_of_sets, size_t number_of_blocks)
{
setarray = (set*)malloc(sizeof(set) * number_of_sets);
}
Generally, when using variables that represent the 'count' or 'size' of objects, an unsigned int is prefereable (unless you can really have a negative count or size).
The warning is produced under very strict warning settings because the value number_of_sets is converted implicitly from int to the unsigned type unsigned long int, which may have a counter-intuitive value for negative values of number_of_sets.
To silence this warning, you can either:
change the prototype of initSetArray to fix the type of the arguments: number_of_sets and numer_of_blocks should probably be unsigned values with type size_t anyway:
void initSetArray(set *setarray, size_t number_of_sets, size_t number_of_blocks)
alternately, you can add an explicit conversion using the cast operator:
void initSetArray(set *setarray, int number_of_sets, int number_of_blocks) {
setarray = (set*)malloc(sizeof(set) * (size_t)number_of_sets);
}
Note however that setting the value of argument setarray has no effect on the caller's variable that is used as an argument to initSetArray. You should either return the pointer or take a pointer to a pointer argument.
I'm writing a program and have gotten a memory location that I have stored as a unsigned int and the length of the mapping as an unsigned int and I want to unmap this.
My following approach generates the warnings:
warning: passing argument 1 of ‘munmap’ makes pointer from integer without a cast [enabled by default]
/usr/include/i386-linux-gnu/sys/mman.h:77:12: note: expected ‘void *’ but argument is of type ‘unsigned int’
and here is causing me the warning:
//startAddr and addrRange are stored as an unsigned int,
void unmap(mapping_t *maps, const int *curSize){
int i = 0;
for (; i < *curSize; i++){
munmap(maps[i].startAddr, maps[i].addrRange);
}
}
My program also crashes when I hit the munmap, but I am assuming that has to deal with the warning in some way
definition of struct mapping_t as requested:
typedef struct mapping{
unsigned int startAddr;
unsigned int endAddr;
unsigned int addrRange;
} mapping_t;
I'm writing a program and have gotten a memory location that I have stored as a unsigned int
Do not do that. Use void *, char *, or even [u]intptr_t. Do not stuff a pointer into an unsigned int. That is wrong. Pointers are not int values and may not be properly represented by an int, which is why you get a warning. Pointers are allowed to be converted to an int per the C standard - which is why you get a warning instead of an actual error - but there's no guarantee that the conversion back to a pointer value results in the same address.
and the length of the mapping as an unsigned int and I want to unmap this.
Do not do this either. Use size_t:
typedef struct mapping{
void *startAddr;
size_t addrRange;
} mapping_t;
You don't need endAddr as you have the start address and the size. If you need the end address, you need to convert startAddr to a char * to compute the end address.
you cannot use unsigned int for pointers. Use void *.
typedef struct mapping{
void * startAddr;
void * endAddr;
unsigned int addrRange;
}
mapping_t;
In the code below get_pic() returns a pointer of uint8_t type.
Then in main(), get_pic() is called and its return value is cast to the variable address which is an unsigned int.
The pointer that get_pic() returns is to a global array which turns out to be at address a8000f80.
My question is that address a8000f80 is a 32 bit number. Therefore, how can the pointer returned by get_pic() point at this address as it is of type uint8_t which is only 8 bits?
//Function declaration
uint8_t* get_pic(int *piclen);
main() {
unsigned int address, value;
address = (unsigned int) get_pic((int*)& value);
}
An uint8_t cannot point anywhere, because it's not a pointer. But an uint_8* (pointer to uint8_t) can.
You probably want this:
uint8_t* get_pic(int *piclen);
main() {
uint8_t *address;
int value;
address = get_pic(&value);
}
get_pic returns a uint8_t *, that is a pointer to uint8_t), therefore the type of address should uint8_t *.
The parameter passed to getpic is of type pointer to int (int*), therefore value should be of type int* too.
It returns a pointer to a value of type uint8_t; this says nothing about the size of the pointer itself.
The size of the pointer has nothing to do with the size of the object, it points to. So, in fact, for most (aka. almost all) implementations, sizeof($anything *) is constant (for any $anything not being a function).
So sizeof(uint8_t _*) == sizeof(uint32_t *) == sizeof(unsigned int *) == sizeof(struct foo *).
uint8_t * get_pic(int * piclen);
This returns a pointer to some data. If that data is uint32_t, then it's save to assign it to a uint32_t *, no cast needed in C (but compilers may warn):
int len;
uint32_t * address = get_pic(&len);
and then, you can access it using standard syntax.
Also note Michael Walzs answer, he wrote in parallel to me ;)