Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
485 views
in Technique[技术] by (71.8m points)

operators - Two logically identical C instructions give different results

EDIT: The answer is, bitwise operations on signed values does weird things!

During a debugging process, I noticed a weird discrepancy, and I have translated it into an easy to read example below.

It would seem to me that var1 and var2 should be identical: after carefully stepping through this on a debugger, it seems that var1 and var2 are identical for the first iteration, but diverge for the second. I discovered this bug while trying to convert the expression for "var2" into assembly, and noticed that my logical translation (which I've displayed with "var1") was giving different results. The calculation for "var1" is, to me, an identical unpicking of the complex expression for "var2" - where am I going wrong?

This was compiled with Visual Community 2019, x64, debug.

// x is an unsigned char, equivalent to the length of the string
// taking the null terminator into account

unsigned char var1 = x;
unsigned char var2 = x;

for (int i = 0; i < x; ++i) {
    unsigned char temp1 = string[i];
    unsigned char temp2 = var1 ^ temp1;
    unsigned char temp3 = table[temp2];

    var1 ^= temp3;
    var2 ^= table[var2 ^ string[i]];
}
question from:https://stackoverflow.com/questions/65892253/two-logically-identical-c-instructions-give-different-results

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In table[var2 ^ string[i]];, the var2 has an unsigned char value of 0 to 255, and string[i] may have a signed char value of ?128 to +127. (We assume eight-bit bytes and two’s complement, which are ubiquitous in modern systems.)

As is usual with most C operators, the integer promotions are applied to the operands, which, in this case, produces int operands. For the unsigned char values 0 to 255, this produces an int with bits set only in the low eight bits. For char values ?128 to ?1, this produces an int with bits set throughout the int, particularly in the high bits.

Then the result of the XOR operation is an int with high bits set, including the sign bit, so it has a negative value. Then table is indexed with a negative subscript, going outside the bounds of the array. And so the behavior is not defined by the C standard.

To remedy this, change the element type of table to unsigned char or convert string[i] to unsigned char before using it in bitwise operations.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...