htonl printing garbage value - c

The variable 'value' is uint32_t
value = htonl(value);
printf("after htonl is %ld\n\n",value);
This prints -201261056
value = htons(value);
printf("after htons is %ld\n\n",value);
This prints 62465
Please suggest what could be the reason?

I guess your input is 500, isn't it?
500 is 2**8+2**7+2**6+2**5+2**4+2**2 or 0x00 0x00 0x01 0xF4 in little endian order.
TCP/IP uses big endian. So after the htonl, the sequence is 0xF4 0x01 0x00 0x00.
If you print it as signed integer, since the first digit is 1, it is negative then. Negative numbers are regarded as complement, The value is -(2**27 + 2**25+2**24+2**23+2**22+2**21+2**20+2**19+2**18+2**17+2**16) == -201261056

Host Order is the order which your machine understands the data (assuming your machine is little endian) correctly. Network Order is Big Endian, which cannot be understood by your system properly. This is the reason for your so called garbage values.
So, basically, there is nothing with the code. : )
Google "Endianness" to get all the details about Big Endian and Little Endian.
Providing some more info, In Big endian, first byte or lowest address will have the most significant byte and in little endian, at the same place, the least significant byte will be present. So, when you use htonl, your first byte will now contain the most significant byte, but your system will think it is as the least significant byte.
Considering the wikipedia example of decimal 1000 (hex 3E8) in big endian will be 03 E8 and in little endian will be E8 03. Now, if you pass 03 E8 to a little machine, it will consider to be decimal 59395.

htonl() and htons() are functions which is used to convert the data from host's endianess to networks endiness.
Network uses big-endian. so if your system is X86, then it is little-endian.
Host to Network byte order(long data) is htonl(). i.e converts 32bit value to network byte order.
Host to Network byte order(short data) is htons(). i.e converts 16bit value to network byte order.
sample program to show how htonl() works as well as effect of using 32bit value in htons() function.
#include <stdio.h>
#include <arpa/inet.h>
int main()
{
long data = 0x12345678;
printf("\n After htonl():0x%x , 0x%x\n", htonl(data), htons(data));
return 0;
}
It will print After htonl():0x78563412 , 0x7856 on X86_64.
Reference:
http://en.wikipedia.org/wiki/Endianess
http://msdn.microsoft.com/en-us/library/windows/desktop/ms738557%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms738556%28v=vs.85%29.aspx

#halfelf>I jut want to put my findings.I just tried the below program with the same
value 500.I guess you have mistakenely mentioned output of LE as BE and vice versa
Actual output i got is 0xf4 0x01 0x00 0x00 as little Endian format.My Machine is
LE
#include <stdio.h>
#include <netinet/in.h>
/* function to show bytes in memory, from location start to start+n*/
void show_mem_rep(char *start, int n)
{
int i;
for (i = 0; i < n; i++)
printf(" %.2x-%p", start[i],start+i);
printf("\n");
}
/*Main function to call above function for 0x01234567*/
int main()
{
int i = 500;//0x01234567;
int y=htonl(i); --->(1)
printf("i--%d , y---%d,ntohl(y):%d\n",i,y,ntohl(ntohl(y)));
printf("_------LITTLE ENDIAN-------\n");
show_mem_rep((char *)&i, sizeof(i));
printf("-----BIG ENDIAN-----\n");/* i just used int y=htonl(i)(-1) for reversing
500 ,so that
i can print as if am using a BE machine. */
show_mem_rep((char *)&y, sizeof(i));
getchar();
return 0;
}
output is
i--500 , y----201261056,ntohl(y):-201261056
_------LITTLE ENDIAN-------
f4-0xbfda8f9c 01-0xbfda8f9d 00-0xbfda8f9e 00-0xbfda8f9f
-----BIG ENDIAN-----
00-0xbfda8f98 00-0xbfda8f99 01-0xbfda8f9a f4-0xbfda8f9b

Related

Compare 2 different hexadecimal

I have a hexadecimal in unsigned char *hex_1 that contains:
hex_1[0] = 0x5b
hex_1[1] = 0x83
hex_1[2] = 0xb6
hex_1[3] = 0xe9
and I want to compare it with a hex value: 1ca0aaf9.
What should I do? Should I create a new character array, split 1ca0aaf9 into 1c ca 0a, then do memcpy()?
EDIT: I actually want them to either tell me whether "THEY ARE THE SAME!" or "THEY ARE NOT THE SAME!".
EDIT 2: I want it to be like hex[0] to be compared with 1c, etc...
Your probably want this:
uint32_t val = *(uint32_t*)(hex_1); // uint32_t is available by #include <stdint.h>
if (val == 0x1ca0aaf9)
{
}
On a big-endian architecture, you are done. On Intel and other little endian architectures you need to decide if that byte array is logicialy meant to be interpreted as in network byte order as 0x5b83b6e9 (‭decimal 1535358697‬). Or if it's meant to be in host byte order (0xe9b6835b) (decimal ‭3921052507‬). If the byte array is in network byte order, then you'll need to swap the bytes. That's what the ntohl function does.
uint32_t val = *(uint32_t*)(hex_1);
val = ntohl(val); // <arpa/inet.h> or <winsock2.h>
if (val == 0x1ca0aaf9)
{
}

Print unsigned short int in hex and decimal C

I've been trying to print unsigned short int values in C with no luck. As far as I know, it's a 16 bit value, so I've tried several different methods to print this 2 bytes together, but I've only been able to print it correctly when doing it byte by byte.
Note that I want to print this 16 bits in both a decimal and hexadecimal format, for example 00 01 as 1, another example would be: 00 ff as 255.
I have this struct:
struct arphdr {
unsigned short int ar_hrd;
unsigned short int ar_pro;
unsigned char ar_hln;
unsigned char ar_pln;
unsigned short int ar_op;
// I'm commenting the following part because I won't need it now
// for the explanation
/* unsigned char __ar_sha[ETH_ALEN];
unsigned char __ar_sip[4];
unsigned char __ar_tha[ETH_ALEN];
unsigned char __ar_tip[4]; */
};
And this function:
void print_ARP_msg(struct arphdr arp_hdr) {
// I need to print the arp_hdr.ar_hrd in both decimal and hex.
printf("Format HW: %04x\n", arp_hdr.ar_hrd);
printf("Format Proto: %04x\n", arp_hdr.ar_pro);
printf("HW Len: %x\n", arp_hdr.ar_hln);
printf("Proto Len: %x\n", arp_hdr.ar_pln);
printf("Command: %04x\n", arp_hdr.ar_op);
}
The print_ARP_msg function returns me this:
Format HW: 0100
Format Proto: 0008
HW Len: 6
Proto Len: 4
Command: 0100
The hex values of the struct are "00 01 08 00 06 04 00 01", so I don't know why it's returning me 0100 in the arp_hdr.ar_hrd value.
Also, I made a function which prints the struct in hex, to make sure that I'm doing it right, and I was able to check, that all the fields where correctly assigned.
PS: before sending this question, I realized that it's printing the correct Hex values but disordered. Could it be related to the little/big endian "difference"?
Could it be related to the little/big endian "difference"?
Yes. If you're dealing with packets that have arrived over a network - and you're printing fields of an ARP packet, so that's exactly what you're doing - you may have to convert from the byte order of the fields as they are when sent over the network to the byte order on the machine on which you're running.
For example:
printf("Format HW: %04x\n", ntohs(arp_hdr.ar_hrd));
In that particular case, you can get away without the ntohs() call on a big-endian machine (SPARC, System/3x0, z/Architecture, PowerPC/Power ISA running AIX, PowerPC/Power ISA running Mac OS X, possibly PowerPC/Power ISA running Linux, etc.), but you can't get away without it on a little-endian machine (anything with an x86 processor, including x86-64 processors, probably most ARM, etc.).
You can use it on both types of processor.
The hex values of the struct are "00 01 08 00 06 04 00 01", so I don't know why it's returning me 0100 in the arp_hdr.ar_hrd value.
Looks like your platform uses the little endian system.
What appears to be 00 01 in memory is interpreted as 01 x 2^8 + 00. In other words, the hex representation of the number is 0100.
ARP packets, like all internet protocol packets, are transmitted in "network order", which is big-endian. The client must use, for example, ntohs (network to host short) to convert from network order to the machine's local byte order, and htons to go the other way.
See man byteorder for details.

Reading SQLite header

I was trying to parse the header from an SQLite database file, using this (fragment of the actual) code:
struct Header_info {
char *filename;
char *sql_string;
uint16_t page_size;
};
int read_header(FILE *db, struct Header_info *header)
{
assert(db);
uint8_t sql_buf[100] = {0};
/* load the header */
if(fread(sql_buf, 100, 1, db) != 1) {
return ERR_SIZE;
}
/* copy the string */
header->sql_string = strdup((char *)sql_buf);
/* verify that we have a proper header */
if(strcmp(header->sql_string, "SQLite format 3") != 0) {
return ERR_NOT_HEADER;
}
memcpy(&header->page_size, (sql_buf + 16), 2);
return 0;
}
Here are the relevant bytes of the file I'm testing it on:
0000000: 5351 4c69 7465 2066 6f72 6d61 7420 3300 SQLite format 3.
0000010: 1000 0101 0040 2020 0000 c698 0000 1a8e .....# ........
Following this spec, the code looks correct to me.
Later I print header->page_size with this line:
printf("\tPage size: %"PRIu16"\n", header->page_size);
But that line prints out 16, instead of the expected 4096. Why? I'm almost certain it's some basic thing that I've just overlooked.
It's an endianness problem. x86 is little-endian, that is, in memory, the least significant byte is stored first. When you load 10 00 into memory on a little-endian architecture, you therefore get 00 10 in human-readable form, which is 16 instead of 4096.
Your problem is therefore that memcpy is not an appropriate tool to read the value.
See the following section of the SQLite file format spec :
1.2.2 Page Size
The two-byte value beginning at offset 16 determines the page size of
the database. For SQLite versions 3.7.0.1 and earlier, this value is
interpreted as a big-endian integer and must be a power of two between
512 and 32768, inclusive. Beginning with SQLite version 3.7.1, a page
size of 65536 bytes is supported. The value 65536 will not fit in a
two-byte integer, so to specify a 65536-byte page size, the value is
at offset 16 is 0x00 0x01. This value can be interpreted as a
big-endian 1 and thought of is as a magic number to represent the
65536 page size. Or one can view the two-byte field as a little endian
number and say that it represents the page size divided by 256. These
two interpretations of the page-size field are equivalent.
It seems an endianness issue. If you are on a little-endian machine this line:
memcpy(&header->page_size, (sql_buf + 16), 2);
copies the two bytes 10 00 into an uint16_t which will have the low-order byte at the lower address.
You can do this instead:
header->page_size = sql_buf[17] | (sql_buf[16] << 8);
Update
For the record, note that the solution I propose will work regardless of the endianness of the machine (see this Rob Pike's Article).

fread of a struct diffrent under solaris and linux

I'm reading in the first Bytes of an File with fread:
fread(&example_struct, sizeof(example_struct), 1, fp_input);
Which ends up with different results under linux and solaris? Whereby the example_struct (Elf32_Ehdr) is part of Standart GNU C Liborary defined in elf.h? I would be happy to know why this happens?
General the struct looks the following:
typedef struct
{
unsigned char e_ident[LENGTH];
TYPE_Half e_type;
} example_struct;
The Debugcode:
for(i=0;paul<sizeof(example_struct);i++){
printf("example_struct->e_ident[%i]:(%x) \n",i,example_struct.e_ident[i]);
}
printf("example_struct->e_type: (%x) \n",example_struct.e_type);
printf("example_struct->e_machine: (%x) \n",example_struct.e_machine);
Solaris output:
Elf32_Ehead->e_ident[0]: (7f)
Elf32_Ehead->e_ident[1]: (45)
...
Elf32_Ehead->e_ident[16]: (2)
Elf32_Ehead->e_ident[17]: (0)
...
Elf32_Ehead->e_type: (200)
Elf32_Ehead->e_machine: (6900)
Linux output:
Elf32_Ehead->e_ident[0]: (7f)
Elf32_Ehead->e_ident[1]: (45)
...
Elf32_Ehead->e_ident[16]: (2)
Elf32_Ehead->e_ident[17]: (0)
...
Elf32_Ehead->e_type: (2)
Elf32_Ehead->e_machine: (69)
Maybe similar to: http://forums.devarticles.com/c-c-help-52/file-io-linux-and-solaris-108308.html
You don't mention what CPU you have in the machines, maybe Sparc64 in the Solaris machine and x86_64 in the Linux box, but I would guess that you're having an endianness issue. Intel, ARM and most other common architectures today are what is known as little-endian, the Sparc architecture is big-endian.
Let's assume we have the value 0x1234 in a CPU register and we want to store it in memory (or on hard drive, it doesn't matter where). Let N be the memory address we want to write to. We will need to store this 16 bit integer as two bytes in memory, here comes the confusing part:
Using a big-endian machine will store 0x12 at address N and 0x34 at address N+1.
A little-endian machine will store 0x34 at address N and 0x12 at address N+1.
If we store a value using a little endian machine and read it back using a big endian machine we will have swapped the two bytes around and you'll get the issue that you are seeing.
Probably because of differences in the structure packing between the two platforms. It's a bad idea to read structures directly (as units) from external media, since issues like these tend to pop up.

Does my AMD-based machine use little endian or big endian?

I'm going though a computers system course and I'm trying to establish, for sure, if my AMD based computer is a little-endian machine? I believe it is because it would be Intel-compatible.
Specifically, my processor is an AMD 64 Athlon x2.
I understand that this can matter in C programming. I'm writing C programs and a method I'm using would be affected by this. I'm trying to figure out if I'd get the same results if I ran the program on an Intel based machine (assuming that is little endian machine).
Finally, let me ask this: Would any and all machines capable of running Windows (XP, Vista, 2000, Server 2003, etc) and, say, Ubuntu Linux desktop be little endian?
All x86 and x86-64 machines (which is just an extension to x86) are little-endian.
You can confirm it with something like this:
#include <stdio.h>
int main() {
int a = 0x12345678;
unsigned char *c = (unsigned char*)(&a);
if (*c == 0x78) {
printf("little-endian\n");
} else {
printf("big-endian\n");
}
return 0;
}
An easy way to know the endiannes is listed in the article Writing endian-independent code in C
const int i = 1;
#define is_bigendian() ( (*(char*)&i) == 0 )
Assuming you have Python installed, you can run this one-liner, which will print "little" on little-endian machines and "big" on big-endian ones:
python -c "import struct; print 'little' if ord(struct.pack('L', 1)[0]) else 'big'"
"Intel-compatible" isn't very precise.
Intel used to make big-endian processors, notably the StrongARM and XScale. These do not use the IA32 ISA, commonly known as x86.
Further back in history, Intel also made the little-endian i860 and i960, which are also not x86-compatible.
Further back in history, the prececessors of the x86 (8080, 8008, etc.) are not x86-compatible either. Being 8-bit processors, endianness doesn't really matter...
Nowadays, Intel still makes the Itanium (IA64), which is bi-endian: normal operation is big-endian, but the processor can also run in little-endian mode. It does happen to be able to run x86 code in little-endian mode, but the native ISA is not IA32.
To my knowledge, all of AMD's processors have been x86-compatible, with some extensions like x86_64, and thus are necessarily little-endian.
Ubuntu is available for x86 (little-endian) and x86_64 (little-endian), with less complete ports for ia64 (big-endian), ARM(el) (little-endian), PA-RISC (big-endian, though the processor supports both), PowerPC (big-endian), and SPARC (big-endian). I don't believe there is an ARM(eb) (big-endian) port.
In answer to your final question, the answer is no. Linux is capable of running on big endian machines like e.g., the older generation PowerMacs.
The below snippet of code works:
#include <stdio.h>
int is_little_endian() {
short x = 0x0100; //256
char *p = (char*) &x;
if (p[0] == 0) {
return 1;
}
return 0;
}
int main() {
if (is_little_endian()) {
printf("Little endian machine\n");
} else printf("Big endian machine\n");
return 0;
}
The "short" integer in the code is 0x0100 (256 in decimal) and is 2 bytes long. The least significant byte is 00, and the most significant is 01. Little endian ordering puts the least significant byte in the address of the variable. So it just checks whether the value of the byte at the address pointed by the variable's pointer is 0 or not.
If it is 0, it is little endian byte ordering, otherwise it's big endian.
You have to download a version of Ubuntu designed for big endian machines. I know only of the PowerPC versions. I'm sure you can find some place which has a more generic big-endian implementation.
/* by Linas Samusas */
#ifndef _bitorder
#define _bitorder 0x0008
#if (_bitorder > 8)
#define BE
#else
#define LE
#endif
and use this
#ifdef LE
#define Function_Convert_to_be_16(value) real_function_to_be_16(value)
#define Function_Convert_to_be_32(value) real_function_to_be_32(value)
#define Function_Convert_to_be_64(value) real_function_to_be_64(value)
#else
#define Function_Convert_to_be_16
#define Function_Convert_to_be_32
#define Function_Convert_to_be_64
#endif
if LE
unsigned long number1 = Function_Convert_to_be_16(number2);
*macro will call real function and it will convert to BE
if BE
unsigned long number1 = Function_Convert_to_be_16(number2);
*macro will be defined as word not a function and your number will be between brackets
We now have std::endian!
constexpr bool is_little = std::endian::native == std::endian::little;
https://en.cppreference.com/w/cpp/types/endian

Resources