Do not use on any
shared computer
July 25, 2008 02:34pm pdt
null
[x]
Attachment Details

C Structure to Char pointer, failure

Tags: C
The code below is used in order to try and cast / convert a structure to a char pointer. Why do i want to do this? I want to print the representing bytes so that i afterwards can cast from a string to a structure.

The following code prints the memory address, and not the representation itself. Suggestions?
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
#include <string.h>
 
typedef struct NetworkFrame_
{
      unsigned ack : 1;
      unsigned tseq : 7;
} NetworkFrame;
 
void main(void)
{
      NetworkFrame nf;
      NetworkFrame * pnf;
      
      char* test;
      
      nf.ack = 1;
      nf.tseq = 12345678;
      
      test = (char*)&nf; // Here you can't the address not the object itself!
 
      pnf = (NetworkFrame *) test;
 
      memcpy(&nf,  test, sizeof(NetworkFrame));
 
	  printf("%x", test);
 
	  system("PAUSE");
}
Start your free trial to view this solution
[x]
The Solution Rating System

With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.

  • The Grade of the Solution
  • The Zone Rank of the Expert Providing the Solution
  • The Number of Author and Expert Comments
  • The Number of Experts Contributing
  • The Feedback of the Community

Your Input Matters
Because of the way the system is set up, the most important variable in this equation is you. As a member of Experts Exchange, you are able to cast your vote on the quality of the solutions in regard to how complete, accurate, helpful and easy to understand each solution is. When you provide your feedback, each rating is adjusted accordingly. So, if you see a solution that has a poor rating that you think is a good solution, let us know by rating it. As you do, the rating will be adjusted and will become more accurate for other members of our site.

If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support.

Thank you!

Question Stats
Zone: Programming
Question Asked By: fraW
Solution Provided By: Infinity08
Participating Experts: 3
Solution Grade: A
Views: 188
Translate:
Loading Advertisement...
 
[+][-]Expert Comment by zhuba
Expert Comment by zhuba:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
[+][-]Accepted Solution by Infinity08

Rank: Sage

Accepted Solution by Infinity08:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
[+][-]Expert Comment by Infinity08

Rank: Sage

Expert Comment by Infinity08:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
[+][-]Expert Comment by lucky_james
Expert Comment by lucky_james:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
[+][-]Expert Comment by Infinity08

Rank: Sage

Expert Comment by Infinity08:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
[+][-]Author Comment by fraW
Author Comment by fraW:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
[+][-]Expert Comment by Infinity08

Rank: Sage

Expert Comment by Infinity08:

All comments and solutions are available to Premium Service Members only.

Start your 7-day free trial and see for yourself why Experts Exchange is the easiest and most proven technology resource in the world. Get Started

Already a member? Login to view this solution.

 
 
Loading Advertisement...
Open Discussion
Open Discussion
null
Comment by fraW
We are implementing a protocol and we receive structures and we just want to cast them to the structs directly, hard to explain but, this is basicly because we want to know how the stuff is placed in memory.

Thanks again
 
null
Comment by Infinity08
If it's just for sending and receiving data, then you can do something like :

        NetworkFrame nf;
        // fill the frame
        send(sd, &nf, sizeof(NetworkFrame), 0);

and :

        recv(sd, &nf, sizeof(NetworkFrame), 0);
 
null
Comment by Infinity08
>> Can't really understand the whole thing

I'm happy to explain : the code iterates over each byte of the network frame (for a total of sizeof(NetworkFrame) bytes, which is the size of the network frame struct), and shows each of those bytes as a hexadecimal value :

          int i = 0;
          for (i = 0; i < sizeof(NetworkFrame); ++i) {
              printf("%02x ", test[i]);
          }

test[i] is the i-th byte of the network frame.
%02x means to print as hexadecimal with 2 digits, and pre-pended by 0's if needed.


Note that you could have simply done this too :

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
NetworkFrame nf;
 
int i = 0;
for (i = 0; i < sizeof(NetworkFrame); ++i) {
    printf("%02x ", ((unsigned char*) &nf)[i]);
}
 
/* OR even : */
 
NetworkFrame nf;
 
unsigned char *ptr = &nf;
int i = 0;
for (i = 0; i < sizeof(NetworkFrame); ++i, ++ptr) {
    printf("%02x ", *ptr);
}
Open in New Window
 
null
Comment by fraW
Its not between methods its over a Radio Transeiver. And the message is encrypted with AES so we need to cast it to a char first and decrypt, then assign the structs. Do you understand? :)
 
null
Comment by Infinity08
>> Do you understand? :)

Sure :)
 
null
Comment by fraW
Oh i see, but,
      unsigned ack : 1;
      unsigned tseq : 7;
should be 1 byte, the loop runs 4 times, is that correct?
 
null
Comment by fraW
Btw, thank you for the very good explenation :D
 
null
Comment by Infinity08
>> should be 1 byte, the loop runs 4 times, is that correct?

1 bit, not one byte. If you need bytes, then you need this struct :

        typedef struct NetworkFrame_
        {
            unsigned char ack[1];
            unsigned char tseq[7];
        } NetworkFrame;

>> the loop runs 4 times, is that correct?

The loop runs for as many times as there are bytes in the struct. If there's no padding in the struct I just posted, it would run 8 times.
 
null
Comment by fraW
This is the ouput:
05 00 00 00 Press any key to continue . . .

Ack is 1 bit and Tseq is 7bits creating 1 byte. Is a struct padded to 4 bytes? That might be why.. hehe

from the following code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
#include <string.h>
 
typedef struct NetworkFrame_
{
	unsigned ack : 1;
	unsigned tseq : 7;
} NetworkFrame;
 
int main(void)
{
      NetworkFrame nf;
      NetworkFrame * pnf;
      
      unsigned char* test;
      int i = 0;
 
      nf.ack = 1;
      nf.tseq = 2;
      
      test = (unsigned char*)&nf;
 
      pnf = (NetworkFrame *) test;
 
      memcpy(&nf,  test, sizeof(nf));
 
 
      for (i = 0; i < sizeof(nf); ++i) 
      {
		  printf("%02x ", test[i]);
      }
 
	  system("PAUSE");
	  
	  return 0;
}
Open in New Window
 
null
Comment by fraW
Follow up question then..

The real networkframe is this:
typedef struct NetworkFrame
{
      unsigned                        ack             : 1;
      unsigned                          tseq            : 7;
      _BYTE                               payload[64];
};

Lets say that i have a long package ( char ) with Hex values: 01ff00ff00ff00ff.... etc..

How do "convert" this to a struct? can i just typecast it? that representation would cause ack to be 1 and tseq to be 0 if im not mistaken.. and the rest in payload.
 
null
Comment by fraW
Oh one more thing, lets say that i have nested structs, is this a problem?

Sorry for the multi posts :)
 
null
Comment by Infinity08
>> Is a struct padded to 4 bytes? That might be why.. hehe

In this case, yes. Structs usually align on word boundaries (and a word is apparently 4 bytes on your system).


>> Lets say that i have a long package ( char ) with Hex values: 01ff00ff00ff00ff.... etc..
>>
>> How do "convert" this to a struct? can i just typecast it?

If you have padding between ack/tseq and the payload, which is a distinct possibility, then it's not as straightforward as just doing a cast. You can usually force the compiler not to use padding (check your compiler documentation), or you can do an explicit copy (which is obviously more expensive than a cast) :

        NetworkFrame nf;
        unsigned char *msg;                            /* the received message */
        memcpy(&nf, msg, 1);                           /* <--- copy the first byte */
        memcpy(&(nf.payload), msg + 1, 64)    /* <--- copy the payload */


>> that representation would cause ack to be 1 and tseq to be 0 if im not mistaken..

The other way around. If you want ack to be 1 and tseq 0, then you need the byte 0x80 instead of 0x01.


>> Oh one more thing, lets say that i have nested structs, is this a problem?

When done correctly, there's no problem. Remember padding !
 
null
Comment by fraW
Oh thank you for the clearification!

Its padded, *sigh*,  this is the output of the following code:
0005 0042 0040 0000 0000 0000 0000 0000

42 and 40 isnt anything that i assign, so i assume its a padding thing, dont understand why though when my struct is ( should be ) 4 bytes?

Is there a simple solution for this?
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
#include <string.h>
 
typedef struct NetworkFrame_
{
	unsigned ack : 1;
	unsigned tseq : 7;
	unsigned char payload[3];
} NetworkFrame;
 
int main(void)
{
      NetworkFrame nf;
      NetworkFrame *pnf;
      
      unsigned char* test;
      int i = 0;
 
      nf.ack = 1;
      nf.tseq = 2;
		
	  nf.payload[0] = 0;
	  nf.payload[1] = 0;
	  nf.payload[2] = 0;
	  nf.payload[3] = 0;
      
      test = (unsigned char*)&nf;
 
      pnf = (NetworkFrame *) test;
 
      memcpy(&nf,  test, sizeof(nf));
 
      for (i = 0; i < sizeof(nf); ++i) {
		  printf("%04x ", test[i]);
      }
 
	  system("PAUSE");
	  
	  return 0;
}
Open in New Window
 
null
Comment by Infinity08
My compiler adds no padding in this case, but a compiler is allowed to add padding if it thinks that that would improve performance or so.


Note that this :

          nf.payload[3] = 0;

is a buffer overflow : the payload array is only 3 bytes, not 4.

Also note that you still have the faulty memcpy there ...


>> 42 and 40 isnt anything that i assign

Padding can contain random data, yes.


>> dont understand why though when my struct is ( should be ) 4 bytes?

The C standard doesn't say that it has to be 4 bytes. Check your compiler documentation - usually there is a way to force the compiler not to add padding (which compiler are you using ?).
 
null
Comment by fraW
Oh okay!

At the moment i am using Visual Studio 2005 but this scenario is supposed to be moved to HiTIDE and using their C Compiler for PIC16 chip.
 
null
Comment by Infinity08
If I'm not mistaken, for Visual Studio, you need to add this line right before the struct definition :

        #pragma pack(1)

which will force alignment on byte boundaries.

        http://msdn2.microsoft.com/en-us/library/2e70t5y1(VS.80).aspx

For the other compiler, you'll have to check in its documentation.
 
null
Comment by fraW
The following code still results:  0005 0042 0040 0000 0000 0000 0000

Can't understand why?
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
#include <string.h>
#include <stddef.h>
 
#pragma pack(1)
typedef struct NetworkFrame_
{
	unsigned ack : 1;
	unsigned tseq : 7;
	unsigned char payload[3];
} NetworkFrame;
 
int main(void)
{
      NetworkFrame nf;
      NetworkFrame *pnf;
      
      unsigned char* test;
      int i = 0;
 
      nf.ack = 1;
      nf.tseq = 2;
		
	  nf.payload[0] = 0;
	  nf.payload[1] = 0;
	  nf.payload[2] = 0;
	  nf.payload[3] = 0;
      
      test = (unsigned char*)&nf;
 
      pnf = (NetworkFrame *) test;
 
      memcpy(&nf,  test, sizeof(nf));
 
      for (i = 0; i < sizeof(nf); ++i) {
		  printf("%04x ", test[i]);
      }
 
	  system("PAUSE");
	  
	  return 0;
}
Open in New Window
 
null
Comment by Infinity08
>> Can't understand why?

Well, bit fields are highly implementation dependent, and I always advise not to use them for interpreting byte streams, especially if the code needs to be portable.


It seems that your compiler insists on allocating an entire unsigned int even though only the first byte is used. Usually compilers have ways of changing the behavior, but I don't know your compiler very well, so I can't tell you how. Check the compiler documentation.
 
null
Comment by fraW
Heh i did check the link you gave me, but without success :) its the compiler that comes with vs2005
 
null
Comment by Infinity08
Did you have any further questions about this ?
 
null
Comment by fraW
Hehe still no success in packing it, but i guess theres no more you can do for me, you've given me all the help you can!

Thank you
 
null
Comment by Infinity08
Apart from telling you that it's not recommended to depend on bitfields for things like this, because they're extremely platform dependent, I can't say much, no, because I don't know the compilers you're using :)
 
 
20080723-EE-VQP-34 / EE_QW_2_20070628