-1

I am trying to copy the word: 0x0FF0 to a buffer but unable to do so.
Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>


void print_bits(unsigned int x);

int main(int argc, char *argv[])
{


    char buffer[512];

    unsigned int init = 0x0FF0;
    unsigned int * som = &init;

    printf("print bits of som now: \n");
    print_bits(init);
    printf("\n");

    memset(&buffer[0], 0, sizeof(buffer)); // reinitialize the buffer
    memcpy(buffer, som, 4); // copy word to the buffer

    printf("print bits of buffer[0] now: \n");
    print_bits(buffer[0]);
    printf("\n");


    return 0;
}

void print_bits(unsigned int x)
{
    int i;
    for (i = 8 * sizeof(x)-17; i >= 0; i--) {
        (x & (1 << i)) ? putchar('1') : putchar('0');
    }
    printf("\n");
}  

this is the result I get in the console:
enter image description here

Why am I getting different values from the bit printing if I am using memcpy?

Don't know if it has something to do with big-little-endian but I am losing 4 bits of 1's here so in both of the methods it shouldn't happen.

Barmar
  • 741,623
  • 53
  • 500
  • 612
David8988
  • 79
  • 1
  • 1
  • 7

3 Answers3

2

When you call

print_bits(buffer[0]);

you're taking just one byte out of the buffer, converting it to unsigned int, and passing that to the function. The other bytes in buffer are ignored.

Barmar
  • 741,623
  • 53
  • 500
  • 612
1

You are not writing the bytes "0F F0" to the buffer. You are writing whatever bytes your platform uses internally to store the number 0x0FF0. There is no reason these need to be the same.

When you write 0x0FF0 in C, that means, roughly, "whatever my implementation uses to encode the number four thousand eighty". That might be the byte string 0F, F0. But it might not be.

I mean, how weird would it be if unsigned int init = 0x0FF0; and unsigned int init = 4080; would do the same thing on some platforms and different things on others? But surely not all platforms store the number 4,080 using the byte string "0F F0".

For example, I might store the number ten as "10" or "ten" or any number of other ways. It's unreasonable for you to expect "ten", "10", or any other particular byte sequence to appear in memory just because you stored the number ten unless you do happen to specifically know how your platform stores the number ten. Given that you asked this question, you don't know that.

Also, you are only printing the value of buffer[0], which is a single character. So it couldn't possibly hold any version of 0x0FF0.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
1

You are mixing up types and relying on specific settings of your architecture/platform; This already breaks your existing code, and it may get even more harmful once you compile with different settings.

Your buffer is of type char[512], while your init is of type unsigned int. First, it depends on the settings whether char is signed or unsigned char. This is actually relevant, since it influences how a char-value is promoted to an unsigned int-value. See the following code that demonstrated the difference using explicitly signed and unsigned chars:

signed char c = 0xF0;
unsigned char uc = c;
unsigned int ui_from_c = c;
unsigned int ui_from_uc = uc;

printf("Singned char c:%hhd; Unsigned char uc:%hhu; ui_from_c:%u ui_from_uc:%u\n", c, uc, ui_from_c,ui_from_uc);
// output: Singned char c:-16; Unsigned char uc:240; ui_from_c:4294967280 ui_from_uc:240

Second, int may be represented by 4 or by 8 bytes (which can hold a "word"), yet char will typically be 1 byte and can therefore not hold a "word" of 16 bit. Third, architectures can be big endian or little endian, and this influences where a constant like 0x0FF0, which requires 2 bytes, would actually be located in a 4 or 8 byte integral representation.

So it is for sure that buffer[0] selects just a portion of that what you think it does, the portion might get promoted in the wrong way to an unsigned int, and it might even be a portion completely out of the 0x0FF0-literal.

I'd suggest to use fixed-width integral values representing exactly a word throughout:

#include <stdio.h>
#include <stdint.h>

void print_bits(uint16_t x);

int main(int argc, char *argv[])
{


    uint16_t buffer[512];

    uint16_t init = 0x0FF0;
    uint16_t * som = &init;

    printf("print bits of som now: \n");
    print_bits(init);
    printf("\n");

    memset(buffer, 0, sizeof(buffer)); // reinitialize the buffer
    memcpy(buffer, som, sizeof(*som)); // copy word to the buffer

    printf("print bits of buffer[0] now: \n");
    print_bits(buffer[0]);
    printf("\n");


    return 0;
}

void print_bits(uint16_t x)
{
    int i;
    for (i = 8 * sizeof(x); i >= 0; i--) {
        (x & (1 << i)) ? putchar('1') : putchar('0');
    }
    printf("\n");
}
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58