十六进制字符串XOR函数内存重叠及输出异常问题求助
我编写了一个接收两个十六进制字符串的myXORFunction函数,功能是对两个字符串逐字节对进行异或(XOR)运算并输出结果(目前仍存在bug),代码如下:
int myXORFunction(char *firstInputString, char *secondInputString){ //This function takes two hex strings of equal length, XORs each pair of bytes and returns the resulting string. char firstReconstructedByte[2] = {0}; char secondReconstructedByte[2] = {0}; char buffer[1]; int firstResult, secondResult, xorResult; if (strlen(firstInputString) != strlen(secondInputString)){ printf("String lengths don't match exiting..."); return 1; }else{ //printf("More code coming soon!\n"); for(int index=0; index != strlen(firstInputString); index = index +2){ firstReconstructedByte[0] = firstInputString[index]; firstReconstructedByte[1] = firstInputString[index+1]; //firstReconstructedByte[2] = 0; firstResult = strtol(firstReconstructedByte, 0, 16); secondReconstructedByte[0] = secondInputString[index]; secondReconstructedByte[1] = secondInputString[index+1]; //secondReconstructedByte[2] = 0; secondResult = strtol(secondReconstructedByte, 0, 16); xorResult = firstResult^secondResult; //printf("First operand is: %s\n", firstReconstructedByte); //printf("Second operand is: %s\n", secondReconstructedByte); printf("Result of XORing %s and %s is: %d\n", firstReconstructedByte, secondReconstructedByte, xorResult); } return 0; } }
该函数原本运行基本正常,但最终打印时firstReconstructedByte无输出,发现是secondReconstructedByte[2] = 0;语句向firstReconstructedByte指向的内存写入了空字节,导致内存重叠。我使用的是Linux环境下的gcc 14.2,输入的firstInputString为1c0111001f010100061a024b53535009181c,secondInputString为686974207468652062756c6c277320657965。
按照建议移除了空字节赋值及数组第3元素的访问操作后,又出现了secondReconstructedByte输出损坏的问题。请问这是编译器bug吗?有没有编译器指令可以让firstReconstructedByte和secondReconstructedByte按字节对齐,避免内存越界干扰?
这不是编译器bug,问题根源在于代码违反了C字符串的基本规则,触发了未定义行为:
- 核心问题:缺少字符串终止符
strtol函数要求传入的参数是一个以空字符\0结尾的合法C字符串,但你定义的firstReconstructedByte和secondReconstructedByte是长度为2的字符数组,刚好只能放下两个十六进制字符,没有多余空间存储终止符。调用strtol时,函数会从数组起始位置一直读取内存,直到遇到空字符,这会读取到数组之外的栈内存(比如相邻变量的空间),导致解析结果错误、输出损坏,甚至程序崩溃。
之前的secondReconstructedByte[2] = 0;属于越界写操作,栈上变量的连续布局可能让这个写操作覆盖了firstReconstructedByte的内存,这也是未定义行为的一种表现。
- 解决方案:修复字符串终止问题
不需要编译器对齐指令,直接修改代码即可解决问题,推荐两种方案:
方案一:扩展数组长度并添加终止符
将临时数组的长度改为3,预留空间存储字符串终止符:
// 修改数组定义为长度3,初始化时自动填充0 char firstReconstructedByte[3] = {0}; char secondReconstructedByte[3] = {0}; // 在赋值后显式设置终止符(可选,初始化已设为0,但显式写更清晰) firstReconstructedByte[0] = firstInputString[index]; firstReconstructedByte[1] = firstInputString[index+1]; firstReconstructedByte[2] = '\0'; // 添加终止符 firstResult = strtol(firstReconstructedByte, 0, 16); // secondReconstructedByte同理 secondReconstructedByte[0] = secondInputString[index]; secondReconstructedByte[1] = secondInputString[index+1]; secondReconstructedByte[2] = '\0'; secondResult = strtol(secondReconstructedByte, 0, 16);
方案二:用sscanf直接解析(更简洁)
跳过临时数组,直接用sscanf从输入字符串中解析两个字符为十六进制值,避免字符串终止符的问题:
// 替换原有的数组赋值和strtol调用 unsigned char firstByte, secondByte; sscanf(&firstInputString[index], "%2hhx", &firstByte); sscanf(&secondInputString[index], "%2hhx", &secondByte); firstResult = firstByte; secondResult = secondByte; xorResult = firstByte ^ secondByte; // 打印时如果需要十六进制字符串,可用printf格式化输出 printf("Result of XORing %02x and %02x is: %d\n", firstByte, secondByte, xorResult);
%2hhx格式符表示读取两个字符,解析为unsigned char类型的值,直接完成十六进制到字节的转换,代码更简洁且无内存越界风险。
- 额外优化:避免循环中重复调用strlen
原代码中for循环的终止条件是index != strlen(firstInputString),每次循环都会调用strlen遍历字符串,影响性能。可以提前计算字符串长度并存储:
size_t strLen = strlen(firstInputString); if (strLen != strlen(secondInputString)) { // ... 长度不匹配处理 } for (int index = 0; index < strLen; index += 2) { // ... 循环逻辑 }
内容的提问来源于stack exchange,提问作者user1801060

