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.
Related
I am currently working on a task where I need to print the address of a variable. It would be easy to use printf %p but I am only allowed to use write from unistd.
I tried casting the pointer in to an unsigned integer and uintptr_t and then converting it into a hexadecimal number. With uintptr_t it works but with an unsigned integer it only prints half of the address. Maybe someone can explain me why this is the case?
I also saw some solutions using ">>" and "<<" but I didn't get why that works. It would be nice if someone can explain a solution using "<<" and ">>" step by step, because I am not sure if I am allowed to use uintptr_t.
this is the code I use to cast it into a unsigned int / unitptr_t / unsigned long long (I know that ft_rec_hex is missing leading 0's):
void ft_rec_hex(unsigned long long nbr)
{
char tmp;
if (nbr != 0)
{
ft_rec_hex(nbr / 16);
if (nbr % 16 < 10)
tmp = nbr % 16 + '0';
else
tmp = (nbr % 16) - 10 + 'a';
write(1, &tmp, 1);
}
}
int main(void)
{
char c = 'd';
unsigned long long ui = (unsigned long long)&c;
ft_rec_hex(ui);
}
It looks like only half of the address is printed because the "unsigned integer" you used has only half size of uintptr_t. (note that uintptr_t is an unsigned integer type)
You can use an array of unsigned char to store data in a pointer variable and print that to print full pointer withput uintptr_t.
Using character types to read objects with other type is allowed according to strict aliasing rule.
#include <stdio.h>
#include <unistd.h>
void printOne(unsigned char v) {
const char* chars = "0123456789ABCDEF";
char data[2];
data[0] = chars[(v >> 4) & 0xf];
data[1] = chars[v & 0xf];
write(1, data, 2);
}
int main(void) {
int a;
int* p = &a;
/* to make sure the value is correct */
printf("p = %p\n", (void*)p);
fflush(stdout);
unsigned char ptrData[sizeof(int*)];
for(size_t i = 0; i < sizeof(int*); i++) {
ptrData[i] = ((unsigned char*)&p)[i];
}
/* print in reversed order, assuming little endian */
for (size_t i = sizeof(int*); i > 0; i--) {
printOne(ptrData[i - 1]);
}
return 0;
}
Or read data in a pointer variable as unsigned char array without copying:
#include <stdio.h>
#include <unistd.h>
void printOne(unsigned char v) {
const char* chars = "0123456789ABCDEF";
char data[2];
data[0] = chars[(v >> 4) & 0xf];
data[1] = chars[v & 0xf];
write(1, data, 2);
}
int main(void) {
int a;
int* p = &a;
/* to make sure the value is correct */
printf("p = %p\n", (void*)p);
fflush(stdout);
/* print in reversed order, assuming little endian */
for (size_t i = sizeof(int*); i > 0; i--) {
printOne(((unsigned char*)&p)[i - 1]);
}
return 0;
}
It would be easy to use printf %p but I am only allowed to use write from unistd.
Then form a string and print that.
int n = snprintf(NULL, 0, "%p", (void *) p);
char buf[n+1];
snprintf(buf, sizeof buf, "%p", (void *) p);
write(1, buf, n);
Using a pointer converted to an integer marginally reduces portability and does not certainly form the best textual representation of the pointer - something implementation dependent.
With uintptr_t it works but with an unsigned integer it only prints half of the address.
unsigned is not specified to be wide enough to contain all the information in a pointer.
uintptr_t, when available (very common), can preserve most of that information for void pointers. Good enough to round-trip to an equivalent pointer, even if in another form.
I'm not sure how to put what I am trying to achieve in words, but I'll just put an example below, hope you guys can lend me a hand!
Basically I'm trying to copy the hex representation of uint64_t value into an unsigned char array, in hex.
What I have:
uint64_t src;
unsigned char destination[8];
/* codes omitted, some codes that will change the value of src */
printf("src: %"PRIx64"\n", src); //this prints out src: 3132333435363738
How do I copy the values from src into destination array in a way that:
destination[0] = 0x31;
destination[1] = 0x32;
destination[2] = 0x33;
//and so on...
Thanks!
EDIT
I'm sorry If my question is unclear, I'm very new to programming and I'm struggling to explain myself.
Basically I'm just trying to store whatever that prints out from that printf() into the unsigned char array as hex.
e.g, printf() outputs a string of "3132333435363738", I want to take 31 and store it in dst[0] where the value of dst[0] will be 0x31, and so on, where dst[1] will be 0x32.
Please bear with me, thanks!
The easy and portable way to extract the bytes that make up an integer in a given order is to just use bit shifts (and possibly masks); in your case, you seem to want to extract your bytes in big-endian order (first byte in destination => most significant byte in src), so that would be:
uint64_t src;
unsigned char destination[8];
for(int i=0; i<8; ++i) {
destination[i] = src>>((7-i)*8);
}
At each iteration, src is shifted to the right by (7-i)*8 bits, because we want the desired byte to go "at the bottom" of the result
First iteration:
src = 0x123456789abcdef0;
i = 0
(7-i) = 7
src >> ((7-i)*8) = 0x12
so, we got 0x12 and we put it into destination[0]; at the next iteration, we have
i = 1
(7-i) = 6
src >> ((7-i)*8) = 0x1234
Now, we could mask the result with 0xFF to take only the bottom 8 bit (namely, 0x34), but that's not important in our case, since each element of destination is an unsigned byte, so when assigning a value larger than 255 (as in this case) it does unsigned overflow, which is well defined to take only the lower bytes that "fit" the target; so, destination[1]=0x34.
Repeat this for i up to 7 and you get the required result.
You can set a pointer to point to the uint64_t itself:
uint64_t src;
unsigned char *view;
view = (unsigned char *)&src;
for (size_t i = 0; i < sizeof(src); ++i) {
printf("%x", view[i]);
}
printf("\n");
If you need to copy the value, not just have another view of it, the same principle applies:
uint64_t src;
unsigned char dst[sizeof(src)];
memcpy((void *)&dst, (void *)&src, sizeof(src));
for (size_t i = 0; i < sizeof(src); ++i) {
printf("%x", dst[i]);
}
printf("\n");
Note that this will inherit the native endianness of the platform. If you want to convert endianness, you can use the library function uint64_t htobe64(uint64_t x) (Linux,BSD) or OSSwapHostToBigInt64(x) (OS X) on src before viewing/copying the string. I don't know the equivalents for Windows but I assume they have them. See I used unsigned char instead of char to avoid any sign extension issues.
Solutions using pointer casts + pointer arithmetic, or solutions using unions will not be portable.
Here is a simple way to do this portably, no matter endianess. There may be more effective ways.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
int main(void)
{
uint64_t src;
uint8_t destination[8] = {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38};
const uint16_t dummy = 1;
const bool is_little_endian = *(const uint8_t*)&dummy == 1;
src=0;
for(size_t i=0; i<8; i++)
{
size_t shift = i*8;
if(is_little_endian)
{
shift = 64-8-shift;
}
src |= (uint64_t)destination[i] << shift;
}
printf("%" PRIx64, src);
return 0;
}
This is essentially the same as the solution given by #Matteo Italia, but using a mask and an explicit cast to the fixed width type uint8_t instead of unsigned char. These solutions should work regardless of endianness, because the bitwise operators work on the value of the left operand, not its underlying representation.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
uint64_t src = 0x3132333435363738;
uint8_t destination[8];
uint64_t mask = 0xff << 56;
size_t i;
for (i = 0; i < 8; i++) {
destination[i] = (uint8_t) ((src & mask) >> (56 - i * 8));
mask >>= 8;
}
printf("src: 0x%" PRIx64 "\n", src);
for (i = 0; i < 8; i++) {
printf("destination[%zu] = 0x%" PRIx8 "\n", i, destination[i]);
}
return 0;
}
Output is:
src: 0x3132333435363738
destination[0] = 0x31
destination[1] = 0x32
destination[2] = 0x33
destination[3] = 0x34
destination[4] = 0x35
destination[5] = 0x36
destination[6] = 0x37
destination[7] = 0x38
I think the title is pretty self explanatory but basically what I'm saying is that, if I have the following instruction:
a = (char) b;
knowing that a's type is char and b's is unsigned char, can that instruction result in making a and b have different binary representations?
The type char can be either signed or unsigned. Char types have no padding, so all bits are value bits.
If char is unsigned, then the value bits of a will be the same as those of b.
If char is signed, then...
if the value of b is representable by char, the common value bits of a and b will the same.
otherwise, the conversion from unrepresentable unsigned char value to char results in an implementation-defined result.
The answer in general, is no, there is no difference. Here you can test it yourself. Just supply the respective values for 'a' and 'b'
#include <stdio.h>
#include <string.h>
const char *byte_to_binary(int x)
{
static char b[9];
b[0] = '\0';
int z;
for (z = 128; z > 0; z >>= 1)
strcat(b, ((x & z) == z) ? "1" : "0");
}
return b;
}
int main(void) {
unsigned char b = -7;
char a = -7;
printf("1. %s\n", byte_to_binary(a));
a = (char) b;
printf("2. %s\n", byte_to_binary(a));
return 0;
}
I have code snippet as Below
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m |= t[p];
printf("%c",m);
m = m << 2;
}
Can anybody help me in solving this. consider i have an ascii value abcd stored in an array t[]. I want to store the same value in 'm'. m is my unsigned int variable . which stores the major number. when i copy the array into m & print m . m should print abcd. can anybody state their logic.
As I understand you, you want to encode the 4 characters into a single int.
Your bit shifting is not correct. You need to shift by 8 bits rather than 2. You also need to perform the shifting before the bitwise or. Otherwise you shift too far.
And it makes more sense, in my view, to print the character rather than m.
#include <stdio.h>
int main(void)
{
const unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(int p=0;p<4;p++)
{
m = (m << 8) | t[p];
printf("%c", t[p]);
}
printf("\n%x", m);
return 0;
}
Why not just look at the t array as an unsigned int?:
unsigned int m = *(unsigned int*)t;
Or you could use an union for nice access to the same memory block in two different ways, which I think is better than shifting bits manually.
Below is an union example. With unions, both the t char array and the unsigned int are stored in the same memory blob. You get a nice interface to each, and it lets the compiler do the bit shifting (more portable, I guess):
#include <stdio.h>
typedef union {
unsigned char t[4];
unsigned int m;
} blob;
int main()
{
blob b;
b.t[0]='a';
b.t[1]='b';
b.t[2]='c';
b.t[3]='d';
unsigned int m=b.m; /* m holds the value of blob b */
printf("%u\n",m); /* this is the t array looked at as if it were an unsignd int */
unsigned int n=m; /* copy the unsigned int to another one */
blob c;
c.m=n; /* copy that to a different blob */
int i;
for(i=0;i<4;i++)
printf("%c\n",c.t[i]); /* even after copying it as an int, you can still look at it as a char array, if you put it into the blob union -- no manual bit manipulation*/
printf("%lu\n", sizeof(c)); /* the blob has the bytesize of an int */
return 0;
}
Simply assign t[p] to m.
m = t[p];
this will implicitly promote char to unsigned int.
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m = t[p];
printf("%c",m);
}
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