#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
*EDIT: I Deleted by mistake the remarks I wrote on that using short & char is kind of obsolete / not efficient in modern programming. this one is just for practice basic stuff.**
This program creates and prints the series of signed short values starting from their equivalent in the unsigned short "space/world" starting at value 0 .
**example : on a machine where short is 16 bit :
unsigned short : 0 1 2 .... 65535
=> signed short : 0 1 2 ... 32766 -32767 -32766 -32765 ... -2 -1
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
//Initialize memory pointed by p with values 0 1 ... n
//Assumption : the value of n can be converted to
// short int (without over/under-flow)
unsigned int initArr (short int *p, unsigned int n);
int main (void)
{
const unsigned int lastNumInSeq = USHRT_MAX;
short *p_arr = (short *) malloc ( (lastNumInSeq + 1) * sizeof (short));
short int lastValSet = initArr (p_arr, lastNumInSeq); //returns the "max" val written
// for (unsigned i = 0; i < numOfElem; i++)
// printf ("[%d]=%d \n", i, (*(p_arr + i)));
printf ("lastValSet = %d *(p_arr + lastNumInSeq) = %d ",
lastValSet,*(p_arr + lastNumInSeq ));
return 0;
}
unsigned int initArr (short *p, unsigned int n)
{
unsigned int offset,index = 0;
while (index <= n){
offset = index;
*(p + offset) = ++index -1 ;
}
return offset;
There are some other cleanups needed.
The function signature should change from
short initArr (short *p, unsigned int n);
to
unsigned int initArr (short *p, unsigned int n);
The variable 'lastValSet' should change its type to unsigned int.
This comment is also confusing:
//Assumption : the value of n can be converted to
// short int (without over/under-flow)
It should be something like:
//Assumption : the value of n which is of type int can be converted to
// short int (without over/under-flow) up to 32767 which is the
// max value for a variable of short type.
I want to copy an unsigned int value to a char[2] variable. I presume the copying is straight forward since both of them have the same size (16 bits). Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned short a = 63488; //16 bit value which is 1111100000000000;
unsigned char* b = malloc(2);
*b = a;
printf("%d\n",b[0]); // I expect the lower part here which is 0
printf("%d\n",b[1]); // I expect the higher part here which is 11111000
return 0;
}
But my result shows zero values. Do I have to copy each part separately? Isn't there any other easier method to do that?
Thank you
If you just want to interpret the short as a char array, you don't even need to copy. Just cast:
#include <stdio.h>
int main()
{
size_t i;
unsigned short a = 63488;
unsigned char* b = (unsigned char*)&a; // Cast the address of a to
// a pointer-to-unsgigned-char
printf("Input value: %d (0x%X)\n", a, a);
printf("Each byte:\n");
for (i = 0; i < sizeof(a); i++)
printf("b[%d] = %d (0x%X)\n", i, b[i], b[i]);
return 0;
}
Output:
$ gcc -Wall -Werror so1.c && ./a.out
Input value: 63488 (0xF800)
Each byte:
b[0] = 0 (0x0)
b[1] = 248 (0xF8)
Note that I ran this on my x86 PC, which is a little endian machine, which is why the first byte is the low byte of the input.
Also note that my code also never makes assumptions about the size of short.
Try like this
memcpy(b, &a, sizeof(a));
Or
b[0] = a & 0xFF;
b[1] = (a >> 8) & 0xFF;
Note that b is of type unsigned char so assigning to *b should be a value of the same type or the value will be truncated.
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.
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