incompatible types in assignment c - c

I have following structs defined in my header file,
struct nl_packet {
int seq;
FRAMETYPE type;
CnetAddr dest;
CnetAddr src;
uint32_t checksum;
size_t length;
char data[NL_MAXDATA];
};
struct seq_Info {
int seqNum;
size_t length;
char data[NL_MAXDATA];
};
struct msg_Received {
CnetAddr src;
struct seq_Info seqInfo[BUFSIZ];
int lastReceived;
};
and then in another file, I have the following assignment that comes with the "incompatible types in assignment error",
msgRec[i].seqInfo[j].data = packet.data;
I do have other statements like this in the same method but they work perfectly fine,
msgRec[i].seqInfo[j].seqNum = packet.seq;
msgRec[i].seqInfo[j].length = packet.length;
Even though both, data fields in nl_packet struct and seq_Info struct have the same type, then is this error coming up ??
Thanks in advance

You are assigning arrays. You can not do that. You have to copy the array contents. You may do it like this:
memcpy(msgRec[i].seqInfo[j].data, packet.data, sizeof(char)*NL_MAXDATA);

Related

C generic inheritance with low verbosity

Having:
struct packet_sample_t {
int common_id;
int some;
char data[];
float foo;
}
Having the following function:
void dispatch_packet(void *packet);
My goal would be to parse the packet id and then call its handler, but I can't retrieve the struct variable common_id from void *.
I would like to create something like an interface in hight level languages, assuming that all my packets structures should have the variable common_id.
So I'm looking something that would work like below:
struct packet_base {
int common_id;
}
void dispatch_packet(void *packet) {
int common_id = ( (packet_base *)packet )->common_id;
switch(common_id) {...}
}
void test() {
packet_sample_t packet = {.common_id = 10, ...};
dispatch_packet((void *) &packet); //this function should retrieve `common_id`
packet_other_t other = {.common_id = 1};
dispatch_packet((void *) &other); // again with another packet
}
Im not that familiar to C language and I dont really know how I could do this. But in simple words, I would like to be able to cast a packet to its packet_base, that are sharing both a common variable.
EDIT: more details in the example
Your technique is valid. There's a number of ways to do struct inheritance in C, and this is one of them. 21st Century C might be a good read for you as well as Object-Oriented Programming with ANSI C.
You have a problems with how you're declaring and using your structs and types. Let's look at this.
struct packet_base {
int common_id;
};
This has the type struct packet_base. If you want to declare a pointer to this type you need to write struct packet_base *packet. If you want to cast a variable of this type it's (struct packet_base *)thing.
This is annoying, so you typically declare a type alias to the struct using typedef. The syntax is typedef <type> <alias>
typedef struct {
int common_id;
} packet_base_t;
That says the type struct { int common_id; } is aliased to packet_base_t. Now you can use packet_base_t as the type. packet_base_t *packet declares a pointer and (packet_base_t *)thing casts.
With that fixed, plus some small errors, it works. See What is the difference between char array vs char pointer in C? for char *data vs char data[].
typedef struct {
int common_id;
int some;
char *data;
float foo;
} packet_sample_t;
typedef struct {
int common_id;
} packet_base_t;
void dispatch_packet(void *arg) {
// It's simpler to cast to a new variable once then to muck
// up the code with casts.
packet_base_t *packet = (packet_base_t *)arg;
int common_id = packet->common_id;
printf("id: %d\n", common_id);
}
You can use union to aggregate the data of different types in a single structure
struct packet1_t
{
// Packet1 specific data
......
}
struct packet2_t
{
// Packet2 specific data
......
}
struct packet_t
{
int common_id;
union
{
struct packet1_t packet1;
struct packet2_t packet2;
......
}
} packet;
Now, based on the ID you can pick the correct type from the union:
int do_something_with_packet(packet_t packet)
{
switch (packet.common_id)
{
case 1:
do_something_with_packet1(packet.packet1);
break;
case 2:
do_something_with_packet2(packet.packet2);
break;
..................
}
....
}

Having type A with N fields is it possible to merge it into new object of type B with N+x fields?

Say we have an instance of
struct Message {
char * topic;
int topicLength;
void * data;
int dataLength;
};
and we want to recreate it as an object of other type
struct CoreMessage {
int messaageId;
char * topic;
int topicLength;
void * data;
int dataLength;
char * senderId;
int senderIdLength;
};
Can we safly turn Message A into CoreMessage B? thing in C without copying contents, having types partly overlaping as shown here?
You can fake this with anonymous structures/unions. Anonymous structures have admittedly only been standardized since C11 but many popular compilers have supported them as an extension for ages.
That is something along these, admittedly-less-than-pretty, lines:
struct Message {
char * topic;
int topicLength;
void * data;
int dataLength;
char * senderId;
int senderIdLength;
};
struct CoreMessage {
int messageId;
union {
struct Message;
struct Message message;
};
};
No, you cannot do what you ask. You could come close, however, if you were willing to change the layout of struct CoreMessage like so:
struct CoreMessage {
struct Message message;
int messaageId;
char * senderId;
int senderIdLength;
};
Note that struct CoreMessage then contains an actual struct Message as a member (as opposed to a pointer to one). Then, given ...
struct CoreMessage cm;
struct CoreMessage *cmp = &cm;
struct Message *mp = &cm.message;
... you have (void *) cmp == (void *) mp, which can be useful for some of the kinds of things you might want to do. This is also adjusts automatically to changes to struct Message.
Alternatively, you can do something like this:
struct Message {
char * topic;
int topicLength;
void * data;
int dataLength;
maximum_alignment_requirement_t resv1;
char resv2[AS_MANY_BYTES_AS_ANY_MESSAGE_TYPE_MAY_NEED_INCLUDING_PADDING];
};
struct CoreMessage {
char * topic;
int topicLength;
void * data;
int dataLength;
maximum_alignment_requirement_t resv1;
int messaageId;
char * senderId;
int senderIdLength;
};
struct Message msg;
struct CoreMessage *cmp = (struct CoreMessage *) &msg;
That has a high probability of working as you would hope (and some system interfaces work pretty much this way) but C does not guarantee that those corresponding elements will be laid out the same way in the two different struct types.
Note, too, that it was no accident that I moved CoreMessage.messageId after the members corresponding to those of struct Message. It is much harder to arrange for corresponding layout if you do not do this, and the pointer value equivalence of the first alternative depends on it.
Not sure what you mean by "safely turn", but I would expect the answer to be "no". The structures are different, of course the smaller one can't magically be expected to expand into memory it didn't previously use.
There is no concept of "overlapping types" in C.
You can of course declare CoreMessage in terms of Message, but it won't help for the reverse transform from the smaller to the larger type except by making the transfer of the shared information easier:
struct CoreMessage {
int messageId;
struct Message message;
char *senderId;
int senderIdLength;
};
Now if we have:
struct Message a = { ... }; /* fully initialized */
struct CoreMessage b; /* we want to convert Message into this */
we can do:
b.messageId = 4711;
b.message = a; /* Copy all Message data over. */
b.senderId = "foo";
b.senderIdLength = 3;
Nothing is automatic here though, you have to do it yourself.
I'm not sure exactly what you mean by "turn into". I'm not sure how you can get casting to do this for you.
But, the C standard allows the compiler to put unused space between fields of a struct so, in general nothing would really work. You could make "CoreMessage" contain a "Message" and produce your result with a single assignment.

Dynamic struct in C

I am trying to read the inputed name, save it in a dynamic struct, add a number at the end if it and count it up. I managed to do the first part, but i cant seem to pass the struct address to the function that should count, nor make the function work.
struct ime_dadoteke
{
unsigned char *ime;
unsigned char velikost;
//this is the struct im working with
};
This is the main:
struct ime_dadoteke *ime;
ime = ime_init();
int i=1;
do
{
naslednje_ime(ime, i); /*here is the problem with passing the
address. I also tried &ime with parameter
struct ime_dodoteke **ptr.
I get error cannot convert argument 1
from 'ime_dadoteke *' to 'ime_dodoteke *' */
i++;
} while (i <= st_korakov);
This is the first function which works:
struct ime_dadoteke* ime_init()
{
int i;
struct ime_dadoteke *rtn = (struct ime_dadoteke*)malloc(sizeof(struct ime_dadoteke));
printf_s("Vnesi ime slike.\n");
rtn->ime =(unsigned char*)malloc(sizeof(unsigned char));
for (i=0; rtn->ime[i-1]!=10; i++)
{
scanf("%c", &rtn->ime[i]);
rtn->ime = (unsigned char*)realloc(rtn->ime, (i+2)*sizeof(unsigned char));
};
rtn->ime[i]='\0';
rtn->velikost = i;
fseek(stdin, 0, SEEK_END);
return rtn;
};
And this is the skeleton of the function that should count the number at the end of the name. I didnt build it yet because i get a problem: pointer to incomplete class is not allowed.
void naslednje_ime(struct ime_dodoteke *ptr, int i)
{
struct ime_dadoteke *ime = ptr;
ptr /*ptr is underlined (error) */->ime[ptr /*ptr is underlined (error) */->velikost - 1] = '0';
};
Also note i created the struct with size of string in it because strlen() doesnt wanna take a non const char. Is there a way around this?
The error message pointer to incomplete class is not allowed means the structure (you told us that referencing members of the struct ime_dadoteke via pointer struct ime_dadoteke *ptr caused the error message) is not defined in the source unit where naslednje_ime is defined. You need to put the struct definition in a header file and include it wherever you use it, also in the file where you define naslednje_ime.

Parsing DNS Response

I am having some trouble with parsing DNS Response. Following is my code. The following are the structures. I'm getting a segmentation fault in the printf(), where im trying to print QNAME.
I'm pretty amateur when it comes to C programming, so im not really sure where im going wrong. Any helps/hints or link to useful resources/tutorials, will be appreciated. The function verfify_header() works correctly. I'm not sure why HEADER is properly extracted using memcpy(). and other fields are not.
struct HEADER{
unsigned short ID;
unsigned char RD:1;
unsigned char TC:1;
unsigned char AA:1;
unsigned char Opcode:4;
unsigned char QR:1;
unsigned char RCODE:4;
unsigned char Z:3;
unsigned char RA:1;
unsigned short QDCOUNT;
unsigned short ANCOUNT;
unsigned short NSCOUNT;
unsigned short ARCOUNT;
};
struct REQ_DATA{
unsigned short qtype;
unsigned short qclass;
};
struct QUESTION{
char* qname;
struct REQ_DATA field;
};
struct RES_DATA{
unsigned short type;
unsigned short class;
unsigned int ttl;
unsigned short rdlength;
};
struct RESPONSE{
char* name;
struct RES_DATA field;
char* rdata;
};
The following is the function that parses the dns response.
void parse_response(char *recvbuf, struct result *res)
{
struct HEADER *rechd = (struct HEADER*) malloc(sizeof(struct HEADER));
struct QUESTION qst;
struct RESPONSE *rp = (struct RESPONSE*) malloc(sizeof(struct RESPONSE));
struct RES_DATA fld;
char* rname = (char*)malloc(sizeof(char));
int hlen,qlen,rlen;
hlen = sizeof(struct HEADER);
memcpy(rechd,recvbuf,hlen);
verify_header(rechd); //This function works correctly
qlen = sizeof(struct QUESTION);
//RESPONSE is after QUESTION and HEADER
rlen = sizeof(struct RESPONSE);
int length = hlen + qlen;
rp = (struct RESPONSE*)(recvbuf + length);
//memcpy(rp, recbbuf + length, sizeof(struct RESPONSE));
memcpy(rname, rp, strlen(rname) + 1);
printf("QNAME: %s\n", *rname); //Segmentation Fault occurs over here!!!!!
}
Thanks,
Chander
The problem is that you're trying to use C structures to parse data from over the network. If your machine is big endian and your compiler happens to order bitfields the way you want them ordered, this might work okay (until you get to the pointer fields...), but it's very fragile. You should be parsing packets as an array of unsigned char.
Now, look at this:
struct QUESTION{
char* qname;
struct REQ_DATA field;
};
This is a structure that's 8 or 16 bytes (depending on your platform), nothing like the variable-length field in the actual DNS packet. And there's certainly no way you're going to get a valid pointer (which would be local to your own machine and process's address space) out of the data off the network.

C programming: Dereferencing pointer to incomplete type error

I have a struct defined as:
struct {
char name[32];
int size;
int start;
int popularity;
} stasher_file;
and an array of pointers to those structs:
struct stasher_file *files[TOTAL_STORAGE_SIZE];
In my code, I'm making a pointer to the struct and setting its members, and adding it to the array:
...
struct stasher_file *newFile;
strncpy(newFile->name, name, 32);
newFile->size = size;
newFile->start = first_free;
newFile->popularity = 0;
files[num_files] = newFile;
...
I'm getting the following error:
error: dereferencing pointer to incomplete type
whenever I try to access the members inside newFile. What am I doing wrong?
You haven't defined struct stasher_file by your first definition. What you have defined is an nameless struct type and a variable stasher_file of that type. Since there's no definition for such type as struct stasher_file in your code, the compiler complains about incomplete type.
In order to define struct stasher_file, you should have done it as follows
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
};
Note where the stasher_file name is placed in the definition.
You are using the pointer newFile without allocating space for it.
struct stasher_file *newFile = malloc(sizeof(stasher_file));
Also you should put the struct name at the top. Where you specified stasher_file is to create an instance of that struct.
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
};
How did you actually define the structure? If
struct {
char name[32];
int size;
int start;
int popularity;
} stasher_file;
is to be taken as type definition, it's missing a typedef. When written as above, you actually define a variable called stasher_file, whose type is some anonymous struct type.
Try
typedef struct { ... } stasher_file;
(or, as already mentioned by others):
struct stasher_file { ... };
The latter actually matches your use of the type. The first form would require that you remove the struct before variable declarations.
the case above is for a new project. I hit upon this error while editing a fork of a well established library.
the typedef was included in the file I was editing but the struct wasn't.
The end result being that I was attempting to edit the struct in the wrong place.
If you run into this in a similar way look for other places where the struct is edited and try it there.
The reason why you're getting that error is because you've declared your struct as:
struct {
char name[32];
int size;
int start;
int popularity;
} stasher_file;
This is not declaring a stasher_file type. This is declaring an anonymous struct type and is creating a global instance named stasher_file.
What you intended was:
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
};
But note that while Brian R. Bondy's response wasn't correct about your error message, he's right that you're trying to write into the struct without having allocated space for it. If you want an array of pointers to struct stasher_file structures, you'll need to call malloc to allocate space for each one:
struct stasher_file *newFile = malloc(sizeof *newFile);
if (newFile == NULL) {
/* Failure handling goes here. */
}
strncpy(newFile->name, name, 32);
newFile->size = size;
...
(BTW, be careful when using strncpy; it's not guaranteed to NUL-terminate.)
The reason is you did not declare type struct stasher_file, you define a struct variable stasher_file
instead.
In C, the declaration of structure:
struct structure-tag {
member1
member2
...
};
structure-tag is an optional name following the keyword struct.
After declaration, you can define a variable:
struct structure-tag var1, *var2;
Also, you can do both declaration and definition like:
struct structure-tag {
member1
member2
...
} var1, *var2;
So in your case, you could try this:
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
} *files[TOTAL_STORAGE_SIZE];
struct stasher_file *newFile = malloc(sizeof(struct stasher_file));
... other code ...
That's all.

Resources