Traversing struct in network byte order(Big Endian) --- C Language
I have a series of structs stored in network byte order. I want to retrieve them. How can I do it.
structs of this type are stored in the file. I want to traverse al开发者_如何转开发l these structs. Any help is greatly appreciated.
Assuming that the int
values are in fact 4 bytes long, then you can use code similar to this:
enum { STRUCT_SIZE = 8 };
void data_reader(FILE *fp)
{
char buffer[STRUCT_SIZE];
struct node data;
while ((fread(buffer, sizeof(buffer), 1, fp) == 1)
{
unpack_struct(buffer, &data);
...stash the unpacked structure...
}
}
void unpack_struct(const char buffer[STRUCT_SIZE], struct node *data)
{
load_int4(&buffer[0], &data->data);
load_int4(&buffer[4], &data->length);
}
void load_int4(const char *data, int *value)
{
*value = ((((data[0] << 8 | data[1]) << 8) | data[2]) << 8) | data[3];
}
There's more than one way to write load_int4()
, but that's compact enough and clear enough for most purposes. It could be made into a macro, or (better) an inline function.
Equally, you can extend this to cover more types: load_int2()
, load_int8()
, maybe unsigned alternatives, etc. You might consider whether plain int
is the best type to use in the structure; it might be better to use the types from <stdint.h>
or <inttypes.h>
such as int32_t
.
I would really like to see what you have written so far. But meanwhile, I'll assume you can convert between endianness (if you don't, Google can provide a ton of tutorials). This leaves you with the task of reading a struct from a file. Right now is not clear to me what length does in your struct. Right now it seems it's just meant to be regular data, so to read a struct you would do something like the following:
struct node
{
int data;
int length;
};
FILE* pFile = fopen( "myfile.bin" , "rb" );
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
char* buffer = (char*) malloc(sizeof(struct node));
if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
size_t result = fread(buffer, 1, sizeof(struct node), pFile);
if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
// 1- perform the conversion from one endianness to another
// 2- convert from char* to node*
node* tmp_struct = (node*)buffer;
printf("data: %d\n", tmp_struct->data);
printf("length: %d\n", tmp_struct->length);
fclose (pFile);
free (buffer);
This code hasn't been tested but it illustrates the tasks of the application. The example above reads only the first available struct in the file. I'll leave the rest as homework for you.
For single Integer
You can use the following endian changing function: x
is the integer of which you want to get the reverse endian, atomicity
is the atomicity of the endian, means the number of bits which are considered as a group. Generally it is 8.
unsigned int toggle_endian (unsigned int x, int atomicity)
{
unsigned int t = 0;
unsigned int mask, sft_amt;
switch (atomicity)
{
case 8:
mask = 0xff;
sft_amt = 8;
break;
case 16:
mask = 0xffff;
sft_amt = 16;
break;
default:
/* Invalid atomicity value, return 0x0 */
return 0x0;
}
while (x)
{
t <<= sft_amt;
t |= (x & mask);
x >>= sft_amt;
}
return t;
}
Also have a look at: http://en.wikipedia.org/wiki/Endianness
EDIT1:
For structure/composite data
For a structure or some type of dynamic size which needs to converted to the reverse endian the following function would help:
your_type conv_endian (your_type x)
{
your_type y;
char *arr = (char *) &x;
char *arr_conv = (char *) &y;
int n, i, j;
n = sizeof (your_type);
for (i=n-1, j=0; i>=0; i--, j++)
{
arr_conv[j] = arr[i];
}
return y;
}
Test the above function with the below driver:
typedef struct _your_type {
unsigned int a, b;
} your_type;
test conv_endian (your_type x);
int main (void)
{
your_type x, y;
x.a = 0x12ab34cd;
x.b = 0x98ef76af;
y = conv_endian (x);
printf ("\n%x %x", x.a, x.b);
printf ("\n%x %x", y.a, y.b);
printf ("\n");
return 0;
}
EDIT2:
For any structure
/* x: base address of the memory
* n: length of the memory
*/
void reverse_endian (void *x, int n)
{
char *arr_conv, *arr, t;
arr = arr_conv = (char *) x;
arr += (n-1);
n/=2;
while (n)
{
t = *arr_conv;
*arr_conv = *arr;
*arr = t;
n--;
arr_conv++;
arr--;
}
}
Check this post Swapping endiannes in C
精彩评论