Converting number to byte array - c

Hi I have a base 10 number for example 3198, and the hex representation is 0x0C7E
How do I convert that number to hex and put that hex value in a byte array in the format of [00][0C][7E], assuming the biggest hex value i can have is 0xffffff.

Maybe this will work ?
uint32_t x = 0x0C7E;
uint8_t bytes[3];
bytes[0] = (x >> 0) & 0xFF;
bytes[1] = (x >> 8) & 0xFF;
bytes[2] = (x >> 16) & 0xFF;
/* Go back. */
x = (bytes[2] << 16) | (bytes[1] << 8) | (bytes[0] << 0);

Number is already a continuous memory block - no need to convert it to yet ANOTHER array ! Just fetch separate bytes by using pointer arithmetic:
EDIT: Edited to be endianness-independent
#define FAST_ABS(x) ((x ^ (x>>31)) - (x>>31))
int is_big_endian(void)
{
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
uint32_t num = 0xAABBCCDD;
uint32_t N = is_big_endian() * 3;
printf("first byte 0x%02X\n"
"second byte 0x%02X\n"
"third byte 0x%02X\n"
"fourth byte 0x%02X\n",
((unsigned char *) &num)[FAST_ABS(3 - N)],
((unsigned char *) &num)[FAST_ABS(2 - N)],
((unsigned char *) &num)[FAST_ABS(1 - N)],
((unsigned char *) &num)[FAST_ABS(0 - N)]
);

#include <stdio.h>
union uint32_value {
unsigned int value;
struct little_endian {
unsigned char fou;
unsigned char thi;
unsigned char sec;
unsigned char fir;
} le;
struct big_endian {
unsigned char fir;
unsigned char sec;
unsigned char thi;
unsigned char fou;
} be;
};
int main(void)
{
union uint32_value foo;
foo.value = 3198;
printf("%02x %02x %02x %02x\n", foo.le.fir, foo.le.sec, foo.le.thi, foo.le.fou);
return 0;
}

Related

How to convert the 4-byte `char` array to one variable of type `unsigned long`?

union sUnion {
unsigned long hex;
float var;
};
void Testcode(void)
{
char rdata[4] = { 0xd7, 0xa3, 0x40, 0xc1 }; // to DEC: -12.04
char ctemp[100];
union sUnion r;
r.hex = 0xc140a3d7; //<=== ??????
sprintf(ctemp, "hex = %x, float = %f", r.hex, r.var);
}
I want to put the data from rdata into the r.hex variable to produce a result of -12.04
If assertion fails change the type of the integer
_Static_assert (sizeof(unsigned long) == 4, "assert1");
#define INTLENGTH sizeof(unsigned long)
//endianess independent
unsigned long covert1(void *varr, int endianness)
{
unsigned char *arr = varr;
unsigned long result;
#define MAXINDEX (INTLENGTH -1)
if(endianess)
result = (unsigned long)arr[0] + ((unsigned long)arr[1] << 8) + ((unsigned long)arr[2] << 16) + ((unsigned long)arr[3] << 24);
else
result = (unsigned long)arr[MAXINDEX - 0] + ((unsigned long)arr[MAXINDEX - 1] << 8) + ((unsigned long)arr[MAXINDEX - 2] << 16) + ((unsigned long)arr[MAXINDEX - 3] << 24);
return result;
}
//arr has to have seme endianness as integers
unsigned long covert(void *arr)
{
unsigned long result;
memcpy(&result, arr, sizeof(result));
return result;
}

Swap alternate bytes in a integer

Problem: swap alternate bytes as below:
Input: uint8_t buf[4] = {0xab,0xcd,0xef,0xba};
Output: 0xcdababef
I have the below code for doing that but I am wondering if there is any better way to shorten the code.
#include <stdint.h>
#define SWAP_16(buf) (((buf & 0xFF00) >> 8) | ((buf & 0x00FF) << 8))
int main()
{
unsigned int value;
int i, j=0;
uint8_t buf[4] = {0,4,0,0};
unsigned int mask = 0xFFFF;
unsigned int tmp_value;
unsigned int size = 4;
for (i = size - 1 ;i >= 0; i--) {
tmp_value |= (buf[j] << 8*i);
j++;
}
value = SWAP_16((tmp_value & (mask << 16)) >> 16) << 16 |
SWAP_16(tmp_value & mask);
return 0;
}
Assuming unsigned int is 32-bits, you can simply use:
value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8);
to swap the bytes in each pair of bytes in value. It's similar to your SWAP_16() macro except that it does both halves of the value at once.
unsigned int forward = 0x12345678;
unsigned int reverse;
unsigned char *f = &forward;
unsigned char *r = &reverse;
r[0]=f[3];
r[1]=f[2];
r[2]=f[1];
r[3]=f[0];
now reverse will be 0x78563412
Here is one way:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint8_t buf[4] = {0xab,0xcd,0xef,0xba};
unsigned int out = buf[1] * 0x1000000u + buf[0] * 0x10000u + buf[3] * 0x100u + buf[2];
printf("%x\n", out);
}
It's not immediately clear from your question if it's not an option, but you could merely just swap the bytes in the array if you know the size won't change:
#include <stdio.h>
#include <stdint.h>
#define SWAPPED(b) { b[1], b[0], b[3], b[2] }
#define PRINT(b) printf("0x0%x\n", *((uint32_t*)b));
int main()
{
uint8_t buf[4] = {8,4,6,1};
uint8_t swapped[4] = SWAPPED(buf);
PRINT(buf);
PRINT(swapped);
return 0;
}
The output for this on my machine is:
0x01060408
0x06010804
This is because of endian-ness and printing an array casted to an integer type, but the bytes are swapped as you ask in your question.
Hope that helps.
Use a union
#include <stdint.h>
#define SWAP_VAR(T, v1, v2) do { \
T v = (v1); \
(v1) = (v2); \
(v2) = v; \
} while (0);
union U32
{
uint32_t u;
unsigned char a[4];
};
uint32_t swap32(uint32_t u)
{
union U32 u32 = {u};
SWAP_VAR(unsigned char, u32.a[0], u32.a[1]);
SWAP_VAR(unsigned char, u32.a[2], u32.a[3]);
return u32.u;
}
Use it like this:
#include <stdint.h>
uint32_t swap32(uint32_t u);
int main(void)
{
uint32_t u = 0x12345678;
u = swap32(u);
}
unsigned int n = ((unsigned int)buf[0] << 16) |
((unsigned int)buf[1] << 24) |
((unsigned int)buf[2] << 0) |
((unsigned int)buf[3] << 8);

Write and read an integer in a char *

I'm coding a little server in c (a chat server) and i want to write and read an integer (and other type of variable like short int, unsigned int blablabla) in my char *data.
I have a structure DataOutput :
typedef struct t_dataoutput
{
char *data;
unsigned int pos;
} DataOutput;
And i have a function to write an int :
int writeInt(DataOutput *out, int i)
{
// here i resize my char *data
out->data[out->pos] = (i >> 24);
out->data[out->pos + 1] = (i >> 16) & 0xff;
out->data[out->pos + 2] = (i >> 8) & 0xff;
out->data[out->pos + 3] = i & 0xff;
out->pos += 4;
}
In my main function i want to try my code :
int main()
{
DataOutput out;
out.writeInt(&out, 9000);
printf("%d\n", (out.data[0] << 24) | (out.data[1] << 16) | (out.data[2] << 8) | (out.data[3]));
}
But the result is not good ... Why ? I don't understand :(
Sorry for my english i'm french ^^ !
Thx for your help !
The DataOutput.data should be forced to unsigned char because char are sometimes signed, depending of the compiler, and shifting signed chars or casting them to int (even implicitly) will propagate the sign bit:
typedef struct t_dataoutput
{
unsigned char *data;
unsigned int pos;
} DataOutput;
The memory for out->data has to be allocated before filled.
You can use realloc in the writeInt function like that:
int writeInt(DataOutput *out, int i)
{
// here i resize my char *data
out->data = realloc(out->data, out->pos + 4);
// TODO: test if out->data == NULL --> not enough memory!
out->data[out->pos] = (i >> 24) & 0xff;
out->data[out->pos + 1] = (i >> 16) & 0xff;
out->data[out->pos + 2] = (i >> 8) & 0xff;
out->data[out->pos + 3] = i & 0xff;
out->pos += 4;
}
Of course I initialize my structure with this function :
void initDataOutput(DataOutput *out)
{
out->data = NULL;
out->pos = 0;
}
But i can't do that :
DataOutput out;
char tmp[4];
out.data = tmp;
out.pos = 0;
Because in my code i could write things like that for example :
DataOutput out;
writeInt(&out, 1);
writeString(&out, "Hello");
sendData(&out);
where the int is a kind of packet id and "Hello" is the connexion message, but if it's an other id it's not the same information in out->data
Oh sorry and I don't understand what you mean when you say : avoid shifting signed integers and chars
I must use an unsigned char *data in my DataOutput structure ?

C packing Integer into a buffer RFC 4506

I'm trying to implement this RFC
4.1. Integer
An XDR signed integer is a 32-bit datum that encodes an integer in
the range [-2147483648,2147483647]. The integer is represented in
two's complement notation. The most and least significant bytes are
0 and 3, respectively. Integers are declared as follows:
int identifier;
(MSB) (LSB)
+-------+-------+-------+-------+
|byte 0 |byte 1 |byte 2 |byte 3 | INTEGER
+-------+-------+-------+-------+
<------------32 bits------------>
and here's my code I need to know if there is a better way to do that ?
void packInteger(char *buf,long int i)
{
if(i>=0) {
*buf++ = i>>24;
*buf++ = i>>16;
*buf++ = i>>8;
*buf++ = i;
}
if(i<0) {
i = i*-1;
i = 1 + (unsigned int)(0xffffffffu - i);
buf[0] = (unsigned int)i>>24;
buf[1] = (unsigned int)i>>16;
buf[2] = (unsigned int)i>>8;
buf[3] = (unsigned int)i;
}
}
long int unpackInteger(char *buf)
{
unsigned long int i2 = ((unsigned long int)buf[0]<<24) |
((unsigned long int)buf[1]<<16) |
((unsigned long int)buf[2]<<8) |
buf[3];
long int i;
// change unsigned numbers to signed
if (i2 <= 0x7fffffffu) { i = i2; }
else { i = -1 - (long int)(0xffffffffu - i2); }
return i;
}
int main(void)
{
char buf[4];
packInteger(buf,-31);
printf("%u %u %u %u\n",buf[0],buf[1],buf[2],buf[3]);
long int n = unpackInteger(buf);
printf("%ld",n);
return 0;
}
if someone on 64 bit system is it working or noT ?
version 2
void packInteger(unsigned char *buf,long int i)
{
unsigned long int j = i; // this will convert to 2's complement
*buf++ = i>>24;
*buf++ = i>>16;
*buf++ = i>>8;
*buf++ = i;
}
You should be using unsigned char for your buffers.
A cast to unsigned in C performs the mathematical equivalent of a conversion to 2s complement, so your pack function can be simplified:
void packInteger(unsigned char *buf, long int i)
{
unsigned long u = i;
buf[0] = (u >> 24) & 0xffUL;
buf[1] = (u >> 16) & 0xffUL;
buf[2] = (u >> 8) & 0xffUL;
buf[3] = u & 0xffUL;
}
Your unpack function seems fine (with the change to unsigned char).

Integer to IP Address - C

I'm preparing for a quiz, and I have a strong suspicion I may be tasked with implementing such a function. Basically, given an IP address in network notation, how can we get that from a 32 bit integer into a string in it's dotted decimal notation (something like 155.247.182.83)...? Obviously we can't be using any type of inet functions either...I'm stumped!
You actually can use an inet function. Observe.
main.c:
#include <arpa/inet.h>
main() {
uint32_t ip = 2110443574;
struct in_addr ip_addr;
ip_addr.s_addr = ip;
printf("The IP address is %s\n", inet_ntoa(ip_addr));
}
The results of gcc main.c -ansi; ./a.out is
The IP address is 54.208.202.125
Note that a commenter said this does not work on Windows.
Here's a simple method to do it: The (ip >> 8), (ip >> 16) and (ip >> 24) moves the 2nd, 3rd and 4th bytes into the lower order byte, while the & 0xFF isolates the least significant byte at each step.
void print_ip(unsigned int ip)
{
unsigned char bytes[4];
bytes[0] = ip & 0xFF;
bytes[1] = (ip >> 8) & 0xFF;
bytes[2] = (ip >> 16) & 0xFF;
bytes[3] = (ip >> 24) & 0xFF;
printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]);
}
There is an implied bytes[0] = (ip >> 0) & 0xFF; at the first step.
Use snprintf() to print it to a string.
Another approach:
union IP {
unsigned int ip;
struct {
unsigned char d;
unsigned char c;
unsigned char b;
unsigned char a;
} ip2;
};
...
char ips[20];
IP ip;
ip.ip = 0xAABBCCDD;
sprintf(ips, "%x.%x.%x.%x", ip.ip2.a, ip.ip2.b, ip.ip2.c, ip.ip2.d);
printf("%s\n", ips);
Hint: break up the 32-bit integer to 4 8-bit integers, and print them out.
Something along the lines of this (not compiled, YMMV):
int i = 0xDEADBEEF; // some 32-bit integer
printf("%i.%i.%i.%i",
(i >> 24) & 0xFF,
(i >> 16) & 0xFF,
(i >> 8) & 0xFF,
i & 0xFF);
This is what I would do if passed a string buffer to fill and I knew the buffer was big enough (ie at least 16 characters long):
sprintf(buffer, "%d.%d.%d.%d",
(ip >> 24) & 0xFF,
(ip >> 16) & 0xFF,
(ip >> 8) & 0xFF,
(ip ) & 0xFF);
This would be slightly faster than creating a byte array first, and I think it is more readable. I would normally use snprintf, but IP addresses can't be more than 16 characters long including the terminating null.
Alternatively if I was asked for a function returning a char*:
char* IPAddressToString(int ip)
{
char[] result = new char[16];
sprintf(result, "%d.%d.%d.%d",
(ip >> 24) & 0xFF,
(ip >> 16) & 0xFF,
(ip >> 8) & 0xFF,
(ip ) & 0xFF);
return result;
}
#include "stdio.h"
void print_ip(int ip) {
unsigned char bytes[4];
int i;
for(i=0; i<4; i++) {
bytes[i] = (ip >> i*8) & 0xFF;
}
printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]);
}
int main() {
int ip = 0xDEADBEEF;
print_ip(ip);
}
From string to int and back
const char * s_ip = "192.168.0.5";
unsigned int ip;
unsigned char * c_ip = (unsigned char *)&ip;
sscanf(s_ip, "%hhu.%hhu.%hhu.%hhu", &c_ip[3], &c_ip[2], &c_ip[1], &c_ip[0]);
printf("%u.%u.%u.%u", ((ip & 0xff000000) >> 24), ((ip & 0x00ff0000) >> 16), ((ip & 0x0000ff00) >> 8), (ip & 0x000000ff));
%hhu instructs sscanf to read into unsigned char pointer; (Reading small int with scanf)
inet_ntoa from glibc
char *
inet_ntoa (struct in_addr in)
{
unsigned char *bytes = (unsigned char *) &in;
__snprintf (buffer, sizeof (buffer), "%d.%d.%d.%d",
bytes[0], bytes[1], bytes[2], bytes[3]);
return buffer;
}
My alternative solution with subtraction :)
void convert( unsigned int addr )
{
unsigned int num[OCTET],
next_addr[OCTET];
int bits = 8;
unsigned int shift_bits;
int i;
next_addr[0] = addr;
shift_bits -= bits;
num[0] = next_addr[0] >> shift_bits;
for ( i = 0; i < OCTET-1; i ++ )
{
next_addr[i + 1] = next_addr[i] - ( num[i] << shift_bits ); // next subaddr
shift_bits -= bits; // next shift
num[i + 1] = next_addr[i + 1] >> shift_bits; // octet
}
printf( "%d.%d.%d.%d\n", num[0], num[1], num[2], num[3] );
}
void ul2chardec(char*pcIP, unsigned long ulIPN){
int i; int k=0; char c0, c1;
for (i = 0; i<4; i++){
c0 = ((((ulIPN & (0xff << ((3 - i) * 8))) >> ((3 - i) * 8))) / 100) + 0x30;
if (c0 != '0'){ *(pcIP + k) = c0; k++; }
c1 = (((((ulIPN & (0xff << ((3 - i) * 8))) >> ((3 - i) * 8))) % 100) / 10) + 0x30;
if (!(c1 =='0' && c0=='0')){ *(pcIP + k) = c1; k++; }
*(pcIP +k) = (((((ulIPN & (0xff << ((3 - i) * 8)))) >> ((3 - i) * 8))) % 10) + 0x30;
k++;
if (i<3){ *(pcIP + k) = '.'; k++;}
}
*(pcIP + k) = 0; // pcIP should be x10 bytes
}

Resources