Print correct format from double value to hexadecimal - c

#include <stdio.h>
typedef unsigned char*pointer;
void show_bytes(pointer start, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
printf("%p\t0x%04x\n",start+i, start[i]);
printf("\n");
}
int main()
{
double a = 4.75;
printf("Double demo by %s on %s %s\n", "Toan Tran", __DATE__, __TIME__);
printf("Double a = %.2f (0x%08x)\n", a, a);
show_bytes((pointer) &a, sizeof(double));
}
Output:
Double demo by Toan Tran on Nov 8 2018 11:07:07
Double a = 4.75 (0x00000100)
0x7ffeee7a0b38 0x0000
0x7ffeee7a0b39 0x0000
0x7ffeee7a0b3a 0x0000
0x7ffeee7a0b3b 0x0000
0x7ffeee7a0b3c 0x0000
0x7ffeee7a0b3d 0x0000
0x7ffeee7a0b3e 0x0013
0x7ffeee7a0b3f 0x0040
For this line:
printf("Double a = %.2f (0x%08x)\n", a, a);
I want it to print out the result of start[i]
The return hexadecimal is not the right value for double.
I want it to return 0x40130000000000...
Please help.

The %x format specifier is expecting an unsigned int argument, but you're passing in a double. Using the wrong format specifier invokes undefined behavior.
To print the representation of a double, you need to print each individual byte as hex using a character pointer. This is exactly what you're doing in show_bytes, and is the proper way to do this.
Also, when printing a pointer with the %p format specifier, you should cast the pointer to void *, which is what %p expects. This is one of the rare cases where a cast to void * is needed.
You might be tempted to do something like this:
printf("%llx", *((unsigned long long *)&a));
However this is a violation of the strict aliasing rule. You would need to use memcpy to copy the bytes to the other type:
static_assert(sizeof(unsigned long long) == sizeof(double));
unsigned long long b;
memcpy(&b, &a, sizeof(a));
printf("%llx", b);
You can also do this with a union:
union dval {
double d;
unsigned long long u;
};
union dval v;
v.d = d;
printf("%llx", v.u);

To allow printing a hex dump of any object, pass its address and length.
void show_bytes2(void *start, size_t size) {
int nibble_width_per_byte = (CHAR_BIT + 3) / 4; // Often 2
unsigned char *mem = start;
// Highest bytes first
for (size_t i = size; i>0; ) {
printf("%0*x", nibble_width_per_byte, mem[--i]);
}
printf("\n");
// Lowest bytes first
while (size--) {
printf("%0*x", nibble_width_per_byte, *mem++);
}
printf("\n");
}
Use "%a" to print the significand of the double in hexadecimal.
int main() {
double a = 4.75;
printf("Double a = %a %e %f %g\n", a, a, a, a);
show_bytes2(&a, sizeof a);
}
Output
Double a = 0x1.3p+2 4.750000e+00 4.750000 4.75
4013000000000000 // I want it to return 0x40130000000000...
0000000000001340

Related

Strange behaviour then swapping values inside pointers

I have this code which is supposed to swap two values inside a_ptr and b_ptr:
// swaps two values inside two variables of any type
void swap(void *a_ptr, void *b_ptr)
{
size_t size = sizeof(void *);
void *tmp = malloc(size);
memcpy(tmp, a_ptr, size);
memcpy(a_ptr, b_ptr, size);
memcpy(b_ptr, tmp, size);
free(tmp);
// char wot0 = 0;
// char wot1 = 0;
// swap(&wot0, &wot1);
}
int main(){
long a = -7;
long b = 99999999;
printf("A: %ld, B: %ld\n", a, b);
swap(&a, &b);
printf("A: %ld, B: %ld\n", a, b);
printf("\n");
short c = -9;
short d = 11111;
printf("C: %hd, D: %hd\n", c, d);
swap(&c, &d);
printf("C: %hd, D: %hd\n", c, d);
printf("\n");
char ca = 'a';
char cx = 'x';
printf("CA: %c CX: %c\n", ca, cx);
swap(&ca, &cx);
printf("CA: %d CX: %c\n", ca, cx);
printf("\n");
char *str0 = "Hello, ";
char *str1 = "World!";
printf("STR0: %s STR1: %s\n", str0, str1);
swap(&str0, &str1);
printf("STR0: %s STR1: %s\n", str0, str1);
printf("\n");
return 0;
}
However the output is:
A: -7, B: 99999999
A: 99999999, B: -7
C: -9, D: 11111
C: -7, D: -9
CA: a CX: x
CA: -9 CX: a
STR0: Hello, STR1: World!
STR0: World! STR1: Hello,
It successfully swaps a and b, and then somehow replaces c with b, and ca with d, how's that even possible?
Also, uncommenting these lines:
// char wot0 = 0;
// char wot1 = 0;
// swap(&wot0, &wot1);
Leads to a segfault, why?
EDIT:
I think I didin't convey my intentions very well. That I basically want to do is swap pointers so that a_ptr points to value inside b, and b_ptr points to value inside a, I don't want to actually copy the values themselves and I think I achieved that somewhat successfully, strings of different lengths (for examples "Foo" and "Hello, World!") get swapped without any issues, I tested that, however I don't understand why some variables don't get swapped and actually point to values outside of that I passed into the function
sizeof(void *); is a constant (usually 4 or 8) and does not give you the size of the object it's pointing at. When you copy size bytes, you are not copying the correct amount for the types used.
You're probably better off by supplying the size of the type to the function:
// swaps two values inside two variables of any type
void swapper(void *a_ptr, void *b_ptr, size_t size)
{
void *tmp = malloc(size);
memcpy(tmp, a_ptr, size);
memcpy(a_ptr, b_ptr, size);
memcpy(b_ptr, tmp, size);
free(tmp);
}
// Generate compilation error if objects of different sizes are used.
// The false switch case (0) can only be defined once so if the sizes
// are not the same, it'll try to redefine "case 0" and fail compiling:
#define compile_assert(_expr) switch (_expr) { case 0: break; case _expr: break; }
#define swap(x,y) do { \
compile_assert(sizeof(*(x)) == sizeof(*(y))); \
swapper((x),(y),sizeof(*(x))); } while (0)
And call it like you aimed to do:
swap(&a, &b);
If you only need to swap fundamental types, you could make different implementations for all of them. This should also make it safer since it's harder to supply pointers to objects of different types this way:
#define SwapBuilder(name,type) \
void name(type *a, type *b) { type tmp = *a; *a = *b; *b = tmp; }
SwapBuilder(swap_char,char)
SwapBuilder(swap_schar,signed char)
SwapBuilder(swap_uchar,unsigned char)
SwapBuilder(swap_short,short)
SwapBuilder(swap_ushort,unsigned short)
SwapBuilder(swap_int,int)
SwapBuilder(swap_uint,unsigned int)
SwapBuilder(swap_long,long)
SwapBuilder(swap_ulong,unsigned long)
SwapBuilder(swap_longlong,long long)
SwapBuilder(swap_ulonglong,unsigned long long)
SwapBuilder(swap_float,float)
SwapBuilder(swap_double,double)
SwapBuilder(swap_longdouble,long double)
// A _Generic to call the correct function:
#define swap(x,y) _Generic((x), \
char* : swap_char, \
signed char* : swap_schar, \
unsigned char* : swap_uchar, \
short* : swap_short, \
unsigned short* : swap_ushort, \
int* : swap_int, \
unsigned int* : swap_uint, \
long* : swap_long, \
unsigned long* : swap_ulong, \
long long* : swap_longlong, \
unsigned long long* : swap_ulonglong, \
float* : swap_float, \
double* : swap_double, \
long double* : swap_longdouble \
)((x),(y))
And you'd still call it with swap(&a, &b);

how to add two large unsigned integer in c

so I'm actually trying to do this exercise;
input two integer number, with a >= 1 and b <= 2 power of 32. find the value of a + b
I know this is a simple task but the things is, for small numbers value it worked correctly ( like 20 + 9 = 29), but for value like 1788909566 + 2626399043 the result is incorrect (it should be 4415308609 but 120341313 came out)
this the code that I worked on :
int main() {
unsigned int a, b;
scanf("%u %u", &a, &b);
printf("%u + %u = %u", a, b, a + b);
return 0;
}
Always use long long data type while dealing with large numbers."%llu" is the format specifier for long long.
unsigned long long is of 8 bytes and stores number in range of 0 to 18,446,744,073,709,551,615
int main() {
unsigned long long a, b;
scanf("%llu %llu" , &a, &b);
printf("%llu + %llu = %llu", a, b, a + b);
return 0;
}
because the result wrapped around.
You need to store the result in the larger integer type, or cast to the larger integer type. You need also to use the correct printf format to print unsigned long long number.
int main() {
unsigned int a, b;
scanf("%u %u", &a, &b);
printf("%u + %u = %llu", a, b, (unsigned long long)a + b);
return 0;
}
int main() {
unsigned int a, b;
unsigned long long c;;
scanf("%u %u", &a, &b);
c = (unsigned long long)a + b;
printf("%u + %u = %llu\n", a, b, c);
return 0;
}

Strange typecast behavior

I have this code:
#include <stdio.h>
int func(unsigned int *a) {
printf("(func) Value: %d\n", *a);
}
int main() {
unsigned char a = 255;
printf("Value: %d\n", a);
printf("Bytes: %d %d %d %d\n\n", *&a, *(&a + 1), *(&a + 2), *(&a + 3));
func((unsigned int *) &a);
return 0;
}
I have the output of this program:
Value: 255
Bytes: 255 0 22 234
(func) Value: -367656705
Why i have negative func value, though the type is unsigned int?
Why i have negative func value, though the type is unsigned int?
int func(unsigned int *a) {
printf("(func) Value: %d\n", *a);
// ^^
}
Because %d does not match type of *a
Because sizeof(unsigned char) and sizeof(unsigned int) are different and can also be platform dependent. For example, unsigned char can be 1 byte. unsigned int can be 4 bytes. When you do your pointer arithmetic, you are possibly looking at other things in the stack frame. C provides you lots of rope to hang yourself with.

Understanding unsigned 0 in C

I am trying to understand number representation in C.
I am working on a code segment which looks like the one below.
#include <stdio.h>
#include <string.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int len)
{
int i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
}
void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_unsigned(short x) {
show_bytes((byte_pointer) &x, sizeof(unsigned));
}
int main(int argc,char*argv[])
{
int length=0;
unsigned g=(unsigned)length;// i aslo tried with unsigned g=0 and the bytes are the same
show_unsigned(g);
show_int(length);
printf("%d",g);//this prints 0
return 0;
}
Here, show_unsigned() and show_int() prints the byte representations of the variables specified as arguments.For int length the byte representation is all zeroes as expected, but for unsigned g, the byte representation is 00 00 04 08.But when I print g with a %d, I get 0(so i suppose the numeric value is interpreted as 0 )
Please could somebody explain how this is happening.
In:
void show_unsigned(short x) {
show_bytes((byte_pointer) &x, sizeof(unsigned));
}
You declared the argument short x which is smaller than int x so you ignored some of the 00 and your print function is displaying adjacent garbage.
You're reading sizeof(unsigned) bytes in a short. short isn't guaranteed to be the same size as unsigned, hence, when reading the bytes next to your short, garbage data is read.
To fix this, either pass your argument as an unsigned, or when using sizeof, use sizeof(short).
what you are doing doesn't make any sense, particularly with the type conversions that you have occurring. Someone else already pointed out my point about the conversion to short
Rather than writing an absurd number of functions try doing this
void show_bytes( void *start, unsigned int len ) {
unsigned char* ptr = (unsigned char *) start;
unsigned int i = 0;
for ( i = 0; i < len; ++i, ++ptr ) {
printf( " %.2x", ptr[0] );
}
}
Instead of calling as you had been just call it like:
show_bytes( (void *)&x, sizeof(x));
And if thats too much typing make a macro out of that. now it works for any type you come up with.

How to combine two 32-bit integers into one 64-bit integer?

I have a count register, which is made up of two 32-bit unsigned integers, one for the higher 32 bits of the value (most significant word), and other for the lower 32 bits of the value (least significant word).
What is the best way in C to combine these two 32-bit unsigned integers and then display as a large number?
In specific:
leastSignificantWord = 4294967295; //2^32-1
printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);
This would print fine.
When the number is incremented to 4294967296, I have it so the leastSignificantWord wipes to 0, and mostSignificantWord (0 initially) is now 1. The whole counter should now read 4294967296, but right now it just reads 10, because I'm just concatenating 1 from mostSignificantWord and 0 from leastSignificantWord.
How should I make it display 4294967296 instead of 10?
It might be advantageous to use unsigned integers with explicit sizes in this case:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint32_t leastSignificantWord = 0;
uint32_t mostSignificantWord = 1;
uint64_t i = (uint64_t) mostSignificantWord << 32 | leastSignificantWord;
printf("%" PRIu64 "\n", i);
return 0;
}
Output
4294967296
Break down of (uint64_t) mostSignificantWord << 32 | leastSignificantWord
(typename) does typecasting in C. It changes value data type to typename.
(uint64_t) 0x00000001 -> 0x0000000000000001
<< does left shift. In C left shift on unsigned integers performs logical shift.
0x0000000000000001 << 32 -> 0x0000000100000000
| does 'bitwise or' (logical OR on bits of the operands).
0b0101 | 0b1001 -> 0b1101
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
my take:
unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>
unsigned long long data64;
data64 = (unsigned long long) high << 32 | low;
printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */
Another approach:
unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>
unsigned long long data64;
unsigned char * ptr = (unsigned char *) &data;
memcpy (ptr+0, &low, 4);
memcpy (ptr+4, &high, 4);
printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */
Both versions work, and they will have similar performance (the compiler will optimize the memcpy away).
The second version does not work with big-endian targets but otoh it takes the guess-work away if the constant 32 should be 32 or 32ull. Something I'm never sure when I see shifts with constants greater than 31.
There's another way using arrays and pointers:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
// Two uint32_t to one uint64_t
uint32_t val1[2] = {1000, 90000};
uint64_t *val1_u64_ptr = (uint64_t*)val1; //intermediate pointer cast to avoid Wstrict-aliasing warnings
uint64_t val2 = *val1_u64_ptr;
printf("val2: %" PRIu64 "\n", val2);
// val2: 386547056641000
// back to uint32_t array from uint64_t
uint64_t val3 = 386547056641000ull;
uint32_t *val4 = (uint32_t*)&val3;
printf("val4: %" PRIu32 ", %" PRIu32 "\n", val4[0], val4[1]);
// val4: 1000, 90000
return 0;
}
This code for me is much easier to understand and read. You are just creating a contiguous space in memory with two 32-bit unsigned int and then this same memory space is read as a single 64-bit unsigned int value and vice-versa. There are no operations involved only memory being read as different types.
EDIT
Forgot to mention that this is great if you already have a 64-bit array read from somewhere then you could easily read everything as 32-bit array pairs:
#include <stdio.h>
#include <inttypes.h>
int main() {
uint64_t array64[] = {
386547056641000ull,
93929935171414ull,
186655006591110ull,
73141496240875ull,
161460097995400ull,
351282298325439ull,
97310615654411ull,
104561732955680ull,
383587691986172ull,
386547056641000ull
};
int n_items = sizeof(array64) / sizeof(array64[0]);
uint32_t* array32 = (uint32_t*)&array64;
for (int ii = 0; ii < n_items * 2; ii += 2) {
printf("[%" PRIu32 ", %" PRIu32 "]\n", array32[ii], array32[ii + 1]);
}
return 0;
}
Output:
[1000, 90000]
[3295375190, 21869]
[22874246, 43459]
[2498157291, 17029]
[3687404168, 37592]
[1218152895, 81789]
[3836596235, 22656]
[754134560, 24345]
[4162780412, 89310]
[1000, 90000]
Using union struct
Still better and more readable would be to use a struct union as from https://stackoverflow.com/a/2810339/2548351:
#include <stdio.h>
#include <inttypes.h>
typedef union {
int64_t big;
struct {
int32_t x;
int32_t y;
};
} xy_t;
int main() {
// initialize from 64-bit
xy_t value = {386547056641000ull};
printf("[%" PRIu32 ",%" PRIu32 "]\n", value.x, value.y);
// [1000, 90000]
// initialize as two 32-bit
xy_t value2 = {.x = 1000, .y = 90000};
printf("%" PRIu64, value.big);
// 386547056641000
return 0;
}
Instead of attempting to print decimal, I often print in hex.
Thus ...
printf ("0x%x%08x\n", upper32, lower32);
Alternatively, depending upon the architecture, platform and compiler, sometimes you can get away with something like ...
printf ("%lld\n", lower32, upper32);
or
printf ("%lld\n", upper32, lower32);
However, this alternative method is very machine dependent (endian-ness, as well as 64 vs 32 bit, ...) and in general is not recommended.
Hope this helps.
This code works when both upper32 and lower32 is negative:
data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);
You could do it by writing the 32-bit values to the right locations in memory:
unsigned long int data64;
data64=lowerword
*(&((unsigned int)data64)+1)=upperword;
This is machine-dependent however, for example it won't work correctly on big-endian processors.
Late at the game, but I needed such a thing similar to represent a numerical base10 string of a 64bit integer on a 32bit embedded env..
So, inspired by Link I wrote this code that can do what asked in the question, but not limiting on base10: can convert to any base from 2 to 10, and can be easly extended to base N.
void stringBaseAdd(char *buf, unsigned long add, int base){
char tmp[65], *p, *q;
int l=strlen(buf);
int da1, da2, dar;
int r;
tmp[64]=0;
q=&tmp[64];
p=&buf[l-1];
r=0;
while(add && p>=buf){
da1=add%base;
add/=base;
da2=*p-'0';
dar=da1+da2+r;
r=(dar>=base)? dar/base: 0;
*p='0'+(dar%base);
--p;
}
while(add){
da1=add%base;
add/=base;
dar=da1+r;
r=(dar>=base)? dar/base: 0;
--q;
*q='0'+(dar%base);
}
while(p>=buf && r){
da2=*p-'0';
dar=da2+r;
r=(dar>=base)? 1: 0;
*p='0'+(dar%base);
--p;
}
if(r){
--q;
*q='0'+r;
}
l=strlen(q);
if(l){
memmove(&buf[l], buf, strlen(buf)+1);
memcpy(buf, q, l);
}
}
void stringBaseDouble(char *buf, int base){
char *p;
int l=strlen(buf);
int da1, dar;
int r;
p=&buf[l-1];
r=0;
while(p>=buf){
da1=*p-'0';
dar=(da1<<1)+r;
r=(dar>=base)? 1: 0;
*p='0'+(dar%base);
--p;
}
if(r){
memmove(&buf[1], buf, strlen(buf)+1);
*buf='1';
}
}
void stringBaseInc(char *buf, int base){
char *p;
int l=strlen(buf);
int da1, dar;
int r;
p=&buf[l-1];
r=1;
while(p>=buf && r){
da1=*p-'0';
dar=da1+r;
r=(dar>=base)? 1: 0;
*p='0'+(dar%base);
--p;
}
if(r){
memmove(&buf[1], buf, strlen(buf)+1);
*buf='1';
}
}
void stringLongLongInt(char *buf, unsigned long h, unsigned long l, int base){
unsigned long init=l;
int s=0, comb=0;
if(h){
comb=1;
init=h;
while(!(init&0x80000000L)){
init<<=1;
init|=(l&0x80000000L)? 1: 0;
l<<=1;
s++;
}
}
buf[0]='0';
buf[1]=0;
stringBaseAdd(buf, init, base);
if(comb){
l>>=s;
h=0x80000000L>>s;
s=sizeof(l)*8-s;
while(s--){
stringBaseDouble(buf, base);
if(l&h)
stringBaseInc(buf, base);
h>>=1;
}
}
}
If you ask for
char buff[20];
stringLongLongInt(buff, 1, 0, 10);
your buff will contain 4294967296

Resources