C代码在查找时与C++不同

5
我有以下代码块(不是由我编写)用于进行ASCII字符到EBCDIC的映射和重新编码。
// Variables.
CodeHeader* tchpLoc = {};
...
memset(tchpLoc->m_ucpEBCDCMap, 0xff, 256);
for (i = 0; i < 256; i++) {
    if (tchpLoc->m_ucpASCIIMap[i] != 0xff) {
        ucTmp2 = i;
        asc2ebn(&ucTmp1, &ucTmp2, 1);
        tchpLoc->m_ucpEBCDCMap[ucTmp1] = tchpLoc->m_ucpASCIIMap[i];
    }
}
< p > CodeHeader 的定义如下:

typedef struct {
    ...
    UCHAR* m_ucpASCIIMap; 
    UCHAR* m_ucpEBCDCMap; 
} CodeHeader;

我遇到问题的方法是

void asc2ebn(char* szTo, char* szFrom, int nChrs)
{
    while (nChrs--)
        *szTo++ = ucpAtoe[(*szFrom++) & 0xff];
}

[注意,unsigned char数组ucpAtoe[256]的内容已在问题末尾附上以供参考]。

现在,我有一个旧的C应用程序和我的C++11转换并行运行,这两个代码都会写入一个巨大的.bin文件,但存在微小的差异,我已经追踪到以上代码。对于两种代码,发生的情况是:

...
    if (tchpLoc->m_ucpASCIIMap[i] != 0xff) {
        ucTmp2 = i;
        asc2ebn(&ucTmp1, &ucTmp2, 1);
        tchpLoc->m_ucpEBCDCMap[ucTmp1] = tchpLoc->m_ucpASCIIMap[i];
    }
i = 32被输入,asc2ebn方法返回ucTmp164'@',对于C和C++变体都是如此。下一个输入是i = 48,对于这个值,asc2ebn方法将ucTmp1返回为240'ð',而C++代码将ucTmp1返回为-16'ð'。我的问题是为什么这个查找/转换会为完全相同的输入和查找数组(以下是复制的)产生不同的结果?在这种情况下,旧的C代码被认为是正确的,因此我希望C++能够为这个查找/转换产生相同的结果。谢谢你的时间。
static UCHAR ucpAtoe[256] = {
    '\x00','\x01','\x02','\x03','\x37','\x2d','\x2e','\x2f',/*00-07*/
    '\x16','\x05','\x25','\x0b','\x0c','\x0d','\x0e','\x0f',/*08-0f*/
    '\x10','\x11','\x12','\xff','\x3c','\x3d','\x32','\xff',/*10-17*/
    '\x18','\x19','\x3f','\x27','\x22','\x1d','\x35','\x1f',/*18-1f*/
    '\x40','\x5a','\x7f','\x7b','\x5b','\x6c','\x50','\xca',/*20-27*/
    '\x4d','\x5d','\x5c','\x4e','\x6b','\x60','\x4b','\x61',/*28-2f*/
    '\xf0','\xf1','\xf2','\xf3','\xf4','\xf5','\xf6','\xf7',/*30-37*/
    '\xf8','\xf9','\x7a','\x5e','\x4c','\x7e','\x6e','\x6f',/*38-3f*/
    '\x7c','\xc1','\xc2','\xc3','\xc4','\xc5','\xc6','\xc7',/*40-47*/
    '\xc8','\xc9','\xd1','\xd2','\xd3','\xd4','\xd5','\xd6',/*48-4f*/
    '\xd7','\xd8','\xd9','\xe2','\xe3','\xe4','\xe5','\xe6',/*50-57*/
    '\xe7','\xe8','\xe9','\xad','\xe0','\xbd','\xff','\x6d',/*58-5f*/
    '\x79','\x81','\x82','\x83','\x84','\x85','\x86','\x87',/*60-67*/
    '\x88','\x89','\x91','\x92','\x93','\x94','\x95','\x96',/*68-6f*/
    '\x97','\x98','\x99','\xa2','\xa3','\xa4','\xa5','\xa6',/*70-77*/
    '\xa7','\xa8','\xa9','\xc0','\x6a','\xd0','\xa1','\xff',/*78-7f*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*80-87*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*88-8f*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*90-97*/
    '\xff','\xff','\xff','\x4a','\xff','\xff','\xff','\xff',/*98-9f*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*a0-a7*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*a8-af*/
    '\xff','\xff','\xff','\x4f','\xff','\xff','\xff','\xff',/*b0-b7*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*b8-bf*/
    '\xff','\xff','\xff','\xff','\xff','\x8f','\xff','\xff',/*c0-c7*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*c8-cf*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*d0-d7*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*d8-df*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*e0-e7*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff',/*e8-ef*/
    '\xff','\xff','\xff','\x8c','\xff','\xff','\xff','\xff',/*f0-f7*/
    '\xff','\xff','\xff','\xff','\xff','\xff','\xff','\xff' };

9
对于 char 类型来说,240-16 是相同的值,对吗? - Joker_vD
3
你尝试过显式使用unsigned char而不是char吗?因为char可以是无符号的也可以是有符号的。 - Shafik Yaghmour
@sharth 不,这里的代码是正确的。ucTmp2 用于“from”索引,而 unTmp1 用于“to”索引。 - MoonKnight
@Killercam:没错,我误读了那两个参数。话虽如此,我认为如果没有一个可编译示例,我们帮助解决这个问题会很困难。可能有某些类型的差异我们无法看到。 - Bill Lynch
@Killercam,我觉得你没有理解Joker_vD的观点。观点在于你的“错误”情况下,ucpAtoe[48]产生的位模式是0xf0。如果将其解释为有符号字符/整数,它的值为-16,但如果将其解释为无符号字符/整数,该模式的值为240。这正好是你所看到的两个值,所以似乎你有一个情况将结果视为有符号,另一个情况将其视为无符号。 - twalberg
显示剩余4条评论
1个回答

2
在C和C++中,标准并不要求char是一个signedunsigned类型,而是由实现定义的。显然,你的C编译器将char定义为unsigned char,而你的C++编译器将其定义为signed char
对于GCC,将char设置为unsigned char的标志是-funsigned-char。对于MSVC,则是/J

感谢您的时间。但这不会强制所有 char 值变为 unsigned 吗?如果是这样,那么这不是我想要的,因为在代码的其他地方有意使用了 char 值... 我已经尝试在 C++ 版本中使用此标志(\J),但这并没有帮助转换。我将重写转换方法 asc2ebn,也许进行模板化... - MoonKnight
@Killercam:你不需要对任何东西进行模板化,只需访问szToszFrom并将其转换为unsigned char *或使您的asc2ebn函数接受unsigned char *。这就是为什么有三种不同类型的charsigned charunsigned char的原因。 - mafso
这并没有解决问题,但让我直接找到了正确的方向,非常感谢。最终,我重载了该方法以同时接受 unsigned char*char*。原因是代码的其他地方采用了 char*,且接受负数索引(!?)- 我需要进一步研究这个问题... 感谢大家的帮助。 - MoonKnight
2
@killercam:在C风格的字符串和C风格字符常量中,你应该只使用char。所以char *output="Hello World";是可以的。当你按值传递字符时,你需要使用signed char或unsigned char,而不是普通的char。普通的char会让你受制于编译器的默认设置。 - SJHowe
非常好的建议。谢谢。我对C++非常陌生,每天都在学习。再次感谢。 - MoonKnight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接