Here's what I'm trying out:

Substitute characters into values with no set left bits;
check if the next position is a vowel(or whatever), turn it into a
value with no right bits set, join the two characters
into a single byte, delete the unused position now.

Here's the code using it, that I'm trying to get to work:

for(int i = 0; i < str.length(); i++)
{  
   /*swaps common letters with stuff in the 32-47 range*/  
   str[i] = Subcipher(str[i]);
         
   if(str[i] < 127)
   {
      /*attempt to bring that common swapped stuff, below 16*/
      str[i] -= 32;
             
      /*check are bounadries!*/
      if(str.length() - 1 != i)
      {
         /*if less/equal than 00001111*/
         if(str[i] < 16)
         {
            /*is it in the alphabet range?*/
            if(str[i + 1] > 96 && str[i + 1] < 118)
            {
               temp = str[i + 1];

               if(temp == 'a') { temp = 128;  join = true; }
               /*...replacing vowels and stuff with no right set bits...*/
               else if(temp == 'u') { temp = 240; join = true; }
                     
               if(join)
               {
                             str[i] |= temp;
                             str.erase(i + 1, 1);
                             join = false;
}   }  }  }  }  }

The problem is that when I attempt to "join" the values, it becomes negative/less than 128, even when I use something like str[i] +=temp; , instead.

Can anyone point out if I'm just being stupid?

BTW, this is a compression algorithm that places vowels into a single byte, using the extended ASCII values to shove them on-top of. The reverse should be simpler, just having to shift stuff back-and-forth by four.

Dani AI

Generated

The symptom you described is not data corruption but signedness and integer-promotion behavior. On many platforms char is a signed 8-bit type, so a byte with the high bit set looks negative when interpreted as a char/int. During expression evaluation a char is promoted to int (preserving sign), bitwise/arithmetic work on the promoted value, and assigning back to char can make the numeric value appear negative even though the underlying bits are what you expected. As hinted, and as pointed out, the portable way to treat bytes as 0..255 is to work with unsigned types.

Practical fixes

  • Read the raw byte as an unsigned 8-bit value before you combine bits, do your bitwise work on that unsigned value, then store the result back. For example:
#include <cstdint>

uint8_t b = static_cast<unsigned char>(s[i]); // 0..255
// combine nibbles / set top bits on 'b' using bitwise ops
b = (b & 0x0F) | other_byte;
s[i] = static_cast<char>(b); // store bits back into string (if you must)
  • Prefer uint8_t/unsigned char (or a std::vector<uint8_t> for binary buffers) when you are working with non-text bytes. Converting an integer to unsigned char is well-defined modulo 2^N; conversions to signed char can be implementation-defined.

Other notes

  • Use bitwise OR to merge bit-fields rather than arithmetic where carries could change bits.
  • When debugging numeric values, print them after casting to an unsigned type so you see 0..255, not negative numbers.
  • If you remove bytes while iterating (erase), either adjust the index or use a while loop to avoid skipping characters.

Your fix of casting/using unsigned types is the right approach — the compression logic can remain the same once you treat the bytes as unsigned during bit operations.

Recommended Answers

All 3 Replies

assuming str is of type 'string', str is of type 'char'. chars will be considered negative whenever the top bit is set. It's not an issue if you are bitwise ORing, as you will get the correct result.

If it annoys you, feel free to cast to unsigned char, as necessary.

assuming str is of type 'string', str is of type 'char'. chars will be considered negative whenever the top bit is set. It's not an issue if you are bitwise ORing, as you will get the correct result.

If it annoys you, feel free to cast to unsigned char, as necessary.

Inaccurate statement. The char type may be signed or unsigned, it's an implementation-dependent issue. All chars with true predicate c > '\0' && c <= '\x7f' (ascii-chars) are converted to positive integers, others may be positive or negative (or zero).
So before any manipulations with char bits assign char value to int or unsigned int to suppress possible left bit sign effect, for example:

int ich;
...
ich = (str[i]&0xFF); // absolutely portable code

I see what I was doing now, thinking backwards again and confusing the ranges of unsigned and signed.
It's working now, all I have to do is fix up my substitution cipher and I have my first working compression algorithm - I feel happy :)
Thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.