当 0xFF 在 char 数组中时,它与下一个 char 一起被读取为整数

When 0xFF is in char array, it gets read as integer along with next char

我在 MS-DOS 上使用 C,特别是 Turbo C,在这里读取我的数字时遇到了一些奇怪的事情。我有一个名为 writeBitmap 的函数,它本质上采用具有路径、x 和 y 大小的结构,然后是精灵的偏移 sheet,以及一个使用此定义每个图像的数组。

我遇到的问题是,当我重复从文件中获取的缓存图像数据时,如果数组的输出以 FF 开头,它总是被读取为整数。我的意思是,如果我的数组中有一个 FF,当我使用 if 语句来测试它是否存在时,它的行为就像它正在读取一个包含 FF 的整数,然后连接下一个字符。这意味着我无法检测到 FF(顺便说一句,这是一个透明字节),因为只要它存在,它就会同时读取它和下一个字节,即使在转换为 char 时也是如此。

这是我的代码,我省略了一些东西,但最重要的是我有这些信息:

#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}
};  

这些是对函数很重要的变量,这是写的函数:

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 指的是另一个已知有效的函数。它只是计算图形模式 0x13 的段和偏移量,然后写入内存。

因此,我目前已将此代码设置为处于调试状态。如果它不是 0xFFFF,我让它打印一些东西,这消除了任何作为整数读取的东西。如果尝试消除任何 0xFF,它不会消除它。

这是屏幕输出:

如您所见,所有不是 0xFF 的内容都打印为 1 字节字符,但如果有 0xFF,它会被读取为整数以及下一个数据字节。

我不知道这怎么会发生。我感觉它可能是我动态分配的数组,但它是 char 类型的,并且每个数组成员一次读取的数据不应多于一个字节。

%x 格式说明符需要 int。 printf() 包括将其参数默认提升为 int。因此,除非您明确告诉它输入应被视为字符,否则它不会。 int 在您的系统上是 16 位,因此打印 2 个字节。

问题的根源在于 char 完全不适合用于除字符以外的任何内容。它具有实现定义的符号性——在 Turbo C 上它与带符号的 char 相同。因此,当您在其中存储大于 0x7F 的值时,您将调用实现定义的转换为 signed char,以负值结束。

解决方案是改用 stdint.h 中的 uint8_t。由于您使用的不是专业的标准 C 工具链,而是侏罗纪时期的非标准工具链,因此您必须 typedef unsigned char uint8_t

当你使用 uint8_t/unsigned char 时,printf 转换为 int 时不会保留任何负号,你会得到预期的输出。