Struct pointer cast as uint8_t * throws an error - c

in my function I allocate memory for and fill a structure called messagePacket
struct messagePacket *packet = malloc(sizeof(struct messagePacket));
//fill
When I try to cast the pointer as a (uint8_t *), gcc throws a warning that says: large integer implicitly truncated to unsigned type
sendBuf(..., (uint8_t *)packet);
I've been able to do the following just fine, and I understand I can use this approach as a workaround. I'm here because I would rather learn from this than work around it.
uint8_t *buf = malloc(sizeof(struct messagePacket));
The size of struct messagePacket = 1209 B. My best guess is that the chunk of memory is super large that I gets stored in a high memory address, such as a 16 bye address? But that doesn't fit with the fact that I can malloc a uint8_t * of the same size.

I guess the compiler notices that your struct is larger than 8bit and using uint8_t you will only address the first byte of the structure.
Since this seems to be intended you could cast to (void *) and then to (uint8_t *).
But you should tell sendBuf the buffer size which is sizeof(struct messagePacket).

I think the warning is about some other argument. Please provide the full code for that line, the prototype for the sendBuf() function, and the full compiler warning for the line in question.
As a general idea, the sendBuf() function should probably use a const void * rather than a const uint8_t * for the data to send. See send() and friends.

Related

Get offset to struct member without using offsetof

I have to add a piece of code to a big code that already exists.
I have a pointer in my code, *Ptr. This pointer is of type, unsigned char.
unsigned char *Ptr;
And I have the below struct.
struct
{
uint8_t tag;
uint16_t data[size];
bool status;
}Test;
Test *TagData;
The pointer is typecasted as below and Now the struct pointer is pointing to the location pointed by the pointer Ptr;
TagData = (Test *)Ptr;
In my code, I will be copying some output values to this structure so that those values get copied to the memory location pointed by *Ptr.
In order to copy some values to the data array in the structure, I need to find the offset to that struct member. I want to do it without using offsetof function. I tried doing the below and I get compiler error.
TagData->data = (uint16_t *) (Ptr + sizeof(TagData->tag));
Can anyone tell how to do this ? And I don't want to use the offsetof function. Is there a simpler way to do this?
No, there's no simpler method than using offsetof, which was designed to do what you need.
Also, offsetof is not a function, but a macro, hiding the pointer arithmetic that you'd do if you didn't use offsetof.
So, clear answer: Since you don't even give a reason, it can't be an overly good reason. Get over it and use offsetof.

Is it valid to call malloc with a pointer of the type of the first member?

I am building a hash library, this library works with different structs and all those structs haves an unsigned type as first member, an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
unsigned hash;
void (*func)(struct data *);
};
struct another_data {unsigned hash; int value;};
static void *hash_insert(const char *text, size_t size)
{
unsigned *hash;
hash = malloc(size);
// *hash = hash(text);
*hash = (unsigned)strlen(text);
return hash;
}
static void func(struct data *data)
{
printf("%u\n", data->hash);
}
int main(void)
{
struct data *data;
data = hash_insert("Some text", sizeof *data);
data->func = func;
data->func(data);
free(data);
return 0;
}
Since the first member of the struct and the struct itself haves the same alignment requirements, is it valid to call malloc with a pointer of the type of the first member in order to reserve space for the entire struct?
unsigned *hash = malloc(size); /* where size is the size of the struct */
EDIT:
In this related question provided by #MohitJain:
struct Msg
{
unsigned int a;
unsigned int b;
};
...
uint32_t* buff = malloc(sizeof(Msg));
// Alias that buffer through message
Msg* msg = (Msg*)(buff);
The strict aliasing rule makes this setup illegal
But in my case I am returning a void * from the function, I can use this (returned) pointer inside main without alignment issues, is this assumption correct?
The rules about effective type and pointer aliasing say that it is fine to convert pointers between a struct (or any other "aggregate") and a pointer of the same type as the first appearing member in the struct. And another rule says that structs are not allowed to have padding in the very beginning.
So it is fine as far as the C standard goes... which doesn't really say much of the quality of the program.
The code does not make much sense. You clearly want to use the whole struct, so why not return a pointer of the struct type? Don't complicate things for the sake of it. You should always avoid using void* when there is no need for it, to increase type safety.
Overall, all these things would sort themselves out in a multi-file project with proper program design. If you had a separate file with the hash type and all functions using that type, there would be no doubt of how to write the program.
malloc is guaranteed to return memory aligned for any type.
Therefore it will work regardless of the alignment requirement of the different subtypes.
Since structure member are allocated in the order they are declared, using
unsigned *hash = malloc(size); /* where size is the size of the struct */
can work if your pourpose is just using the hash data.
It fails if you want to apply pointer aritmetic on it, so in this case using
hash++
is an undefined behavior.
Yes it is perfectly fine for first member type to point to the memory returned by malloc (Memory is aligned for any data type). What you do with this memory later may cause issues if you are not careful.
[Extracts from Joachim Pileborg's answer # Maintaining an array of pointers in C that points to two related types with minor changes]
Having a structure inside other structures or a common data type in other structures is a common way of emulating inheritance in C. This common member should contain the minimal set of data common to all structures in the "inheritance" hierarchy, and it must always be the first member in the inheriting structures.
Possible issue with this scheme is:
This "inheritance" scheme will work on all modern PC-like systems and their compilers, and have done so for a long time, but there's no guarantee that it will work on all systems and all compilers (if you're planning on porting the code to some rare system with weird hardware and compiler you might want to look out, but the cases where the "inheritance" scheme will not work is very small, and most people will never come in contact with such a system in their entire lifetime.) But once you point the same memory with struct data *, you may fall victime of strict aliasing rule. So you need to be careful there. Further readL What is the strict aliasing rule?
unsigned *hash = malloc(size);
This will create allocate an array of unsigned integers. Total number of integers allocated will be size/sizeof(int). hash here is pointer to int.
Since the first member of the struct and the struct itself haves the same alignment requirements, is it valid to call malloc with a pointer of the type of the first member in order to reserve space for the entire struct?
The point is, that hash here is a separate variable which has nothing to do with the hash inside the structure. (It is in a separate namespace, if you want to look it up)
You can then cast hash to the struct variable.
struct data *data;
unsigned *hash = malloc(size * sizeof(struct));
data = (struct data *) hash;
But, what is the point. You can just as well remove the unnecessary unsigned hash pointer and go with the traditional.
struct data *data;
data = malloc(size * sizeof(struct));

Suspicious pointer-to-pointer conversion (area too small) in C

uint8_t *buf;
uint16_t *ptr = (uint16_t *)buf;
I feel the above code is correct but I get "Suspicious pointer-to-pointer conversion (area too small)" Lint warning. Anyone knows how to solve this warning?
IMHO, don't cast the pointer at all. It changes the way (representation) a variable (and corresponding memory) is accessed, which is very problematic.
If you have to, cast the value instead.
Its a problem in your code
In line uint8_t buf you must have assigned it with an memory area which is 8 bits long
and then in line uint16_t *ptr = (uint16_t *)buf; you try to assign it to a pointer that will access it as 16 bits.
When you try to access with ptr variable you are acessing memory beyond what is assigned to you and its a undefined behaviour.
The problem here is strict aliasing. Imagine that when you have a case like this:
uint8_t raw_data [N]; // chunk of raw data
uint16_t val = 1;
memcpy(raw_data, &val, sizeof(val)); // copy an uint16_t into this array
uint16_t* lets_go_crazy = (uint16_t*)raw_data;
*lets_go_crazy = 5;
print(raw_data);
Assume the print function prints all the values of the bytes. You might then think that the two first bytes have changed to contain your machine's representation of an uint16_t containing the value 5. Not necessarily so.
Because the compiler on the other hand is free to assume that you have never modified the raw_data array since the memcpy, because an uint16_t is not allowed to alias an uint8_t. So it might optimize the whole code into something like:
uint8_t raw_data [N]; // chunk of raw data
uint16_t val = 1;
memcpy(raw_data, &val, sizeof(val)); // copy an uint16_t into this array
print(raw_data);
What will happen is undefined, because the strict aliasing was broken.
Though note that your code might be perfectly fine if, and only if, you can guarantee that your particular compiler does not apply strict aliasing to whatever scenario you have. There are compiler options to disable it on some compilers.
Alternatively, you could use a pointer to a struct or union containing an uint16_t, in which case the aliasing does not apply.

Difference between two malloc definition of a struct

I would like to know if there's a real difference between this:
c = (struct_t *) malloc(sizeof(struct_t));
and this
c = malloc(sizeof(struct_t *));
Besides avoid the cast, is the compiler takes any advantage in the second form respect the first? Or the two ways are completely the same and is just a "aesthetical" question ?
The first allocates sizeof(struct_t) bytes, the second sizeof(struct_t*) bytes.
Apart from that, there is no difference in what malloc does, whether you cast the result or not. Casting the result makes the code acceptable to C++ compilers, but it can hide the mistake of not including stdlib.h, therefore it is widely preferred to not cast the result in C.
The two are totally different. The first allocates an instance of the struct, whereas the second allocates a pointer to the struct.
In general, they won't even allocate the same number of bytes.
No, they are not the same. The latter allocates 4 or 8 bytes of space for a pointer to struct, the first allocates enough space for the struct it self.
When sizeof(struct_t) is small enough, and when the malloc allocates actually more than requested, the user may not see the difference.
Two forms are different. They both allocate memory, but with different amounts.
General rule is as follows:
when allocating type T, the result of malloc shall be casted to T*.
void sample1()
{
struct pollfd *pfd = (struct pollfd*)malloc(sizeof(struct pollfd));
// pfd is points to a memory with a size of struct pollfd
...
free(pfd);
}
void sample2()
{
struct pollfd *pfd = (struct pollfd*)malloc(sizeof(*pfd));
// same as above, but uses variable type instead
free(pfd);
}
If you specify incorrect type in malloc argument, generally that will lead to buffer overrun problems:
void sample3()
{
struct x *px= (struct x*)malloc(sizeof(struct x*));
x->field = 5; //<< error, as allocated only 4 or 8 bytes depending on pointer size
}
Both are different.
Usually malloc returns (void*). So you want to typecast void* to (struct_t*).

Store pointer address in malloced memory

This feels like a silly question, but I just can't work out a clean solution and can't find a similar question in the mass of other pointer related questions.
I have some dynamically allocated memory of unknown type and want to store a pointer inside it at the start. Dynamic memory returned by malloc should be suitably aligned so I don't think I have to worry about alignment when writing to the start of the allocated block.
This is my code, which works, but I'm representing a pointer as a 64-bit integer and want to do it in a more clean/portable way:
void *my_area = malloc(512);
void *my_pointer = get_my_pointer();
((long long *) my_area)[0] = (long long) my_pointer;
The cast to long long is just extra baggage. Cast to void * instead.
void *my_area = malloc(512);
void *my_pointer = get_my_pointer();
((void **) my_area)[0] = my_pointer;
(I assume that this is for some kind of freelist or the like, i.e., you don't need to use the structure at the same time.)
What will be found in my_area[0] is pointer to something, right ?
Then you can allocate my_area to be of type void **, which represent a pointer to a pointer containing memory area.
void **my_area = malloc(512 * sizeof(*my_area)); // alloc 512 pointer sized memory blocks
void *my_pointer = get_my_pointer();
my_area[0] = my_pointer;
Define a struct with internal array of 8 bytes. Replace all the long long type references with your custom struct. This way you will not depend on platform-specific size of long long. The struct will be 64 bits on all platforms(you can add #pragma pack if you worry about alignment )

Resources