4
\$\begingroup\$

A function that prints out the values of each of the bytes of a variable, which value is given from stdin. Consists of size detector and a loop.

#include <stdio.h>
#include <math.h>

int main(void)
{
    unsigned char uint_8;
    unsigned short uint_16;
    unsigned long uint_32;
    unsigned long long uint_64, n = 0;

    int i;
    size_t size;

    printf("Enter a number: ");
    scanf("%lld", &n);

    if(n < 257) size = 1;
    if(n < 256*256 && n > 256) size = 2;
    if(n < 256*256*256 && n > 256*256) size = 3;
    if(n < pow(256, 4) && n > pow(256, 3)) size = 4;

    for(i = 0; i < size; i++)
    {
        unsigned char* p = (((unsigned char*)&n) + i);
        printf("byte(%i) : %i\n", i, *p);
    }

    return 0;
}

I don't like the size detection though, it could be more safely coded with one line of bit operations I believe.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

A couple of remarks:

  1. You should check the return value of scanf. It returns the number of items successfully converted. You initialize n with 0 so any invalid input will yield in a single 0 output but it might be good to indicate failure anyway.

  2. Using EXIT_SUCCESS and EXIT_FAILURE are more portable ways to indicate success/failure upon return to the OS.

  3. 256 is is not representable by an 8-bit type. The binary representation is 1 0000 0000 - so the 9th bit is set. An 8 bit unsigned type can only hold 0 - 255.

  4. Multiplying an integer by a power of 2 can be done by a left-shift. So 2^5 for example is 1 << 5 - this eliminates any need for multiplication or even invoking pow.

  5. You print out the order of bytes in big endian notation (the highest ordered byte is printed out with the smallest index) while for example x86 is a little endian architecture where the lowest ordered byte has the smallest index. Actually scratch that. The data in memory is laid out little endian so your code will print it in little endian order.

  6. Your size detection works on the assumption that a char is 8 bit. This is not guaranteed by the C standard which requires CHAR_BIT to be at least 8. For example there DSPs where CHAR_BIT is 16 and in the past there were architectures with 9 and 12 bit bytes.

  7. Your size detection only goes up to 4 bytes however unsigned long long is 8 bytes on many platforms. So if someone puts a large number in the it will simply omit the upper 4 bytes.

In the end the size detection can be generalized by finding which byte is the most significant byte - which boils down to finding the most significant bit (the highest bits which is 1). There are a bunch of clever operations to make this really fast but the simplest is to shift right until all set bits are shifted out:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void)
{
    unsigned long long n = 0;
    unsigned long long temp;
    int most_significant_bit = 0;
    int most_significant_byte = 0;
    int i;

    printf("Enter a number: ");
    if (scanf("%lld", &n) != 1)
    {
        printf("Invalid number entered.");
        return EXIT_FAILURE;
    }

    temp = n;
    while (temp >>= 1)
    {
        ++most_significant_bit;
    }
    most_significant_byte = (most_significant_bit / CHAR_BIT) + 1;

    for(i = 0; i < most_significant_byte; i++)
    {
        unsigned char* p = (((unsigned char*)&n) + i);
        printf("byte(%i) : %i\n", i, *p);
    }

    return EXIT_SUCCESS;
}
\$\endgroup\$
2
  • \$\begingroup\$ If I type 24 the program prints 8 bytes, starting from 0-7. This is not the intended behavior though. \$\endgroup\$ Commented Feb 9, 2015 at 20:05
  • \$\begingroup\$ @Genis: Actually I got the endianess thing wrong. Fixed my answer \$\endgroup\$ Commented Feb 9, 2015 at 23:44

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.