1

As part of my CS course I've been given some functions to use. One of these functions takes a pointer to unsigned chars to write some data to a file (I have to use this function, so I can't just make my own purpose built function that works differently BTW). I need to write an array of integers whose values can be up to 4095 using this function (that only takes unsigned chars).

However am I right in thinking that an unsigned char can only have a max value of 256 because it is 1 byte long? I therefore need to use 4 unsigned chars for every integer? But casting doesn't seem to work with larger values for the integer. Does anyone have any idea how best to convert an array of integers to unsigned chars?

Alf_InPogform
  • 53
  • 1
  • 2
  • 4
  • 2
    Count the number of bits you need to represent 4095. It isn't 4 bytes worth. – Hans Passant Jan 07 '11 at 20:49
  • Include the function prototype in your question; that will make it clerer what your assignment requred and get you a better answer. – Clifford Jan 07 '11 at 22:42
  • 1
    But sometimes it's easier to dump sizeof(int) bytes for each int. That way you can run through the array without having to adjust the pointer after each data item when re-reading. – Martin York Jan 07 '11 at 23:12

7 Answers7

5

Usually an unsigned char holds 8 bits, with a max value of 255. If you want to know this for your particular compiler, print out CHAR_BIT and UCHAR_MAX from <limits.h> You could extract the individual bytes of a 32 bit int,

#include <stdint.h>

void
pack32(uint32_t val,uint8_t *dest)
{
        dest[0] = (val & 0xff000000) >> 24;
        dest[1] = (val & 0x00ff0000) >> 16;
        dest[2] = (val & 0x0000ff00) >>  8;
        dest[3] = (val & 0x000000ff)      ;
}


uint32_t
unpack32(uint8_t *src)
{
        uint32_t val;

        val  = src[0] << 24;
        val |= src[1] << 16;
        val |= src[2] <<  8;
        val |= src[3]      ;

        return val;
}
Ed S.
  • 122,712
  • 22
  • 185
  • 265
nos
  • 223,662
  • 58
  • 417
  • 506
  • You can drop the most significant 2 bytes from this. The value `4095` fits very comfortably in 16 bits. – dawg Jan 07 '11 at 21:05
  • 1
    There is no need to do any processing to get the values into an array of char. – Martin York Jan 07 '11 at 23:10
  • An 8 bit value has a max value of 2^8 - 1, (i.e. 255), not 256. The number of total possible values is 256, 0-255. – Ed S. Jan 07 '11 at 23:18
3

Unsigned char generally has a value of 1 byte, therefore you can decompose any other type to an array of unsigned chars (eg. for a 4 byte int you can use an array of 4 unsigned chars). Your exercise is probably about generics. You should write the file as a binary file using the fwrite() function, and just write byte after byte in the file.

The following example should write a number (of any data type) to the file. I am not sure if it works since you are forcing the cast to unsigned char * instead of void *.

int homework(unsigned char *foo, size_t size)
{
    int i;

    // open file for binary writing
    FILE *f = fopen("work.txt", "wb");
    if(f == NULL)
        return 1;

    // should write byte by byte the data to the file
    fwrite(foo+i, sizeof(char), size, f);

    fclose(f);
    return 0;
}

I hope the given example at least gives you a starting point.

Cristian Toader
  • 96
  • 1
  • 1
  • 5
0

Yes, you're right; a char/byte only allows up to 8 distinct bits, so that is 2^8 distinct numbers, which is zero to 2^8 - 1, or zero to 255. Do something like this to get the bytes:

int x = 0;
char* p = (char*)&x;
for (int i = 0; i < sizeof(x); i++)
{
    //Do something with p[i]
}

(This isn't officially C because of the order of declaration but whatever... it's more readable. :) )

Do note that this code may not be portable, since it depends on the processor's internal storage of an int.

user541686
  • 205,094
  • 128
  • 528
  • 886
0

It sounds like what you really want to do is call sprintf to get a string representation of your integers. This is a standard way to convert from a numeric type to its string representation. Something like the following might get you started:

char num[5]; // Room for 4095

// Array is the array of integers, and arrayLen is its length
for (i = 0; i < arrayLen; i++)
{
    sprintf (num, "%d", array[i]);

    // Call your function that expects a pointer to chars
    printfunc (num);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nick.beer
  • 143
  • 1
  • 7
  • This depends on whether you want to store the int *value* in the file or not. If you're output file is supposed to be binary storage for the data this won't do it, but if you just want to save the int in a readable format this is fine. – Stephen P Jan 07 '11 at 20:46
  • sprintf here expects a null terminated array of characters for its "%s" parameter. If any of the bytes are 0, this wont work right. It also wont work because it will run off the end of the array without adding a 0 to the end. – Null Set Jan 07 '11 at 20:47
  • My mistake - I meant the format string to be %d. Edited to fix. – nick.beer Jan 07 '11 at 21:09
0

The part of the assignment of: integers whose values can be up to 4095 using this function (that only takes unsigned chars should be giving you a huge hint. 4095 unsigned is 12 bits.

You can store the 12 bits in a 16 bit short, but that is somewhat wasteful of space -- you are only using 12 of 16 bits of the short. Since you are dealing with more than 1 byte in the conversion of characters, you may need to deal with endianess of the result. Easiest.

You could also do a bit field or some packed binary structure if you are concerned about space. More work.

dawg
  • 98,345
  • 23
  • 131
  • 206
0

Without information on the function you are directed to use regarding its arguments, return value and semantics (i.e. the definition of its behaviour) it is hard to answer. One possibility is:

Given:

void theFunction(unsigned char* data, int size);

then

int array[SIZE_OF_ARRAY];
theFunction((insigned char*)array, sizeof(array));

or

theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(*array));

or

theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(int));

All of which will pass all of the data to theFunction(), but whether than makes any sense will depend on what theFunction() does.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Clifford
  • 88,407
  • 13
  • 85
  • 165
0

If you have to write an array of integers then just convert the array into a pointer to char then run through the array.

int main()
{
    int    data[] = { 1, 2, 3, 4 ,5 };
    size_t size   = sizeof(data)/sizeof(data[0]); // Number of integers.

    unsigned char* out = (unsigned char*)data;
    for(size_t loop =0; loop < (size * sizeof(int)); ++loop)
    {
         MyProfSuperWrite(out + loop);  // Write 1 unsigned char
    }
}

Now people have mentioned that 4096 will fit in less bits than a normal integer. Probably true. Thus you can save space and not write out the top bits of each integer. Personally I think this is not worth the effort. The extra code to write the value and processes the incoming data is not worth the savings you would get (Maybe if the data was the size of the library of congress). Rule one do as little work as possible (its easier to maintain). Rule two optimize if asked (but ask why first). You may save space but it will cost in processing time and maintenance costs.

Martin York
  • 257,169
  • 86
  • 333
  • 562