I would use kbw's code and change the type of currentByte to unsigned char. That code you're using there doesn't look very good (that if seems really out of place). |
Helios is correct. I wasn't trying to fix your program -- just trying to show you where the fundamental error was. There is more work involved in really fixing it. KBW's solution is close, and more elegant, but doesn't tell the whole story; you will
need to do a comparison, and I'll explain why.
If you have a character in
a[i]
that is in the extended ascii range (-1 through -128), the sign bit is set. So rather than explicitly checking that one particular bit, you can compare
a[i] < 0
. If true, then
a[i] >> 7 = 1
. They are equivalent. I suspect, however, that this:
currentBit = a[i] >> 7;
is significantly faster than this:
currentBit = (a[i] < 0) ? 1 : 0;
as Helios already pointed out.
So here's the rub. In your code, you are grabbing that sign bit, and looping around to the first bit, and storing it there like a pseudo-stack that you're going to pop off when you decrypt the text:
encrypt:
1 2 3 4 5 6 7 8 9
|
for(int i = 0; i < length; i++)
{
currentByte = a[i];
currentBit = (currentByte < 0); // true if sign bit, false if not
currentByte = currentByte << 1;
if(currentBit) // this will be true if extended ascii, false otherwise
currentByte+=1; // store the fact of sign bit in 1's place
a[i] = currentByte; // store the character into the array
}
|
Your current code is NOT checking whether the sign bit is already set after your right shift, so in order for your code to be 100%, you absolutely need to check the sign bit before doing anything else. If you stored a 1 in the 1's place when encrypting, that means the
initial unencrypted value of currentByte was negative, i.e. in the extended ascii range. Therefore, your final unencrypted value
must ALSO be < 0, so you can't just +=128. You first have to check to see if the sign bit was set by your bitshift left when you first encrypted, and you can do that by comparing to < 0 again, or by >> 7.See explanation in the code.
decrypt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
for(int i = 0; i<length; i++)
{
currentByte = a[i];
currentBit = currentByte & 1; // if the first bit is set, currentBit = true
currentByte >> 1; // moves your bits back over, but doesn't change sign bit
if(currentBit) // if true, then this char value was initially < 0
{
if(currentByte>=0) // value needs sign bit reset
currentByte+=128; // replaces the sign bit
}
else // the initial value was not extended ascii, therefore > 0
{
if(currentByte<0) // it got set during bit shift left << in encryption, turn off
currentByte +=128; // turn off the sign bit
}
a[i] = currentByte;
}
|
The reason the original code I posted worked was because, as I said, for NORMAL input (keystrokes) you can probably not expect to find
a[i] < 0
. In the event you might encounter those characters, you need to use the code above. It's "written out" so you can see what each piece of the logic is examining, but can be simplified using logical operators. You can also turn the sign bit on and off with (XOR) ^-128, but I don't think you gain anything by it.
Hope this helps explain it better. Helios and kbw called it, though. kbw had it nailed in his first post.