I am using C on MS-DOS, specifically Turbo C, and I encountered something strange with my numbers being read here. I have a function called writeBitmap that in essence takes a struct with a path, x and y size, and then offset for a sprite sheet, as well as an array that defines each image using this.
The problem I am having is when I reiterate over the cached image data I get from a file, the output from the array always gets read as if it were an integer if it starts with FF. What I mean by this, is if there is an FF in my array, when I use an if statement to test to see if it's there it acts like it's reading an integer containing the FF, and then the next character concatenated. This means that I can't detect an FF (which is a transparency byte by the way) because whenever it's present, it reads it and then the next byte at the same time, even when casted to a char.
Here is my code, I am omitting some stuff, but up top I have this information:
#include <dos.h>
#include <stdio.h>
/* define structs */
struct imageFile {
char path[16];
unsigned short size_x;
unsigned short size_y;
char offset;
};
/*define globals */
struct imageFile imgMap[1] =
{
{"./OUTP.DAT", 24, 24, 8}
};
These are the variables that are important to the function, and this is the function as written:
void writeBitmap(unsigned x, unsigned y, unsigned id){
int i, j, k;
int imgSize = (imgMap[id].size_x * imgMap[id].size_y); /*get size, init cache, and open file to offset*/
char *imgCache = (char *)malloc(imgSize);
FILE *fimg;
if(x + imgMap[id].size_x > 321 || y + imgMap[id].size_y > 201){
return;
}
fimg = fopen(imgMap[id].path, "rb");
fseek(fimg, (imgMap[id].offset * imgSize), SEEK_SET);
fread(imgCache, 1, imgSize, fimg);
fclose(fimg);
k = 0;
for(i = 0; i < imgMap[id].size_y; i++){
for(j = 0; j < imgMap[id].size_x; j++){
if((char)imgCache[k] != 0xFFFF){
/*setPixel(x + j, y + i, (char)imgCache[k]);*/
printf("%x ", imgCache[k]);
}/*else printf("TRANS: %x\n", imgCache[k]);*/
k++;
}
printf("\n");
}
}
setPixel refers to another function that is known working. It just calculates segment and offset for graphics mode 0x13 and then writes to memory.
So, I currently have this code set up in a bit of a debug state. I have it print something if it's not 0xFFFF, which eliminates anything read as an integer. If try to eliminate anything that's 0xFF, it doesn't eliminate it.
Here's the screen output from that:
As you can see, everything that's not 0xFF gets printed as a 1 byte char, but if there is a 0xFF, it gets read like it's an integer along with the next byte of data.
I have no clue how this could even happen. I have a feeling it might be my dynamically allocated array, but it's of type char, and it shouldn't read more data than a byte at a time per array member.
The %x
format specifier expects an int
. printf() includes default argument promotion of its arguments to int
. So unless you explicitly tells it that the input should be treated as a char, it won't. int
is 16 bits on your system, therefore 2 bytes get printed.
The root of the problem is that char
is entirely unsuitable to use for anything but characters. It has implementation-defined signedness - on Turbo C it was the same as signed char. So when you store a value larger than 0x7F in it, you invoke an implementation-defined conversion to signed char
, ending up with a negative value.
The solution is to use uint8_t
from stdint.h
instead. Since you aren't using a professional standard C toolchain, but rather a non-standard one from the Jurassic period, you have to typedef unsigned char uint8_t
instead.
When you use uint8_t
/unsigned char
, there won't be any negative sign preservation in printf's conversion to int
and you'll get the expected output.