2016-08-16 19 views
1

У меня есть следующий код в C, который будет генерировать ключи на основе входного серийного номера.Побитовое дополнение символа в C# vs C overflowexception

unsigned int32 passkey(unsigned int32 snumber) 
{ 
    char snstring[11]; 
    unsigned int32 pwd; 
    int i = 0; 
    itoa(snumber,10,snstring); 
    do{ 
     snstring[i+1] -= '0'; 
     snstring[i] = ~snstring[i+1]; 
     snstring[i] &= 0x07; 
     i++; 
    }while(i < 9); 
    snstring[9] <<= 1; 
    snstring[9] &= 0x07; 
    pwd = atoi32(snstring); 
    return (pwd); 
} 

Мне нужно преобразовать это в C# код, я попытался следующее:

private uint ComputeKey(uint snumber) 
     { 
      char[] snstring = new char[11]; 
      UInt32 pwd; 
      int i = 0; 
      snstring = snumber.ToString().ToCharArray(); 

      do 
      { 
       snstring[i + 1] = Convert.ToChar(snstring[i + 1] - '0'); 
       snstring[i] = Convert.ToChar(~Convert.ToInt32(snstring[i + 1])); 
       snstring[i] &= Convert.ToChar(Convert.ToInt32(0x07)); 
       i++; 
      } while (i < 9); 
      snstring[9] <<= 1; 
      snstring[9] &= Convert.ToChar(0x07); 
      pwd = Convert.ToUInt32(snstring); 
      return (pwd); 
     } 

Программы бросает исключение в snstring[i] = Convert.ToChar(~Convert.ToInt32(snstring[i + 1])); этой линии.

Другого заметное поведения является то, что, например, у меня есть вклад в

Затем на этой линии snstring[i] = Convert.ToChar(~Convert.ToInt32(snstring[i + 1])); значения snstring[i+1] является '\u0005' И бросает OverflowException было Неизвестное.

Я не уверен, что я должен делать, любая помощь приветствуется.

+0

Результат '~ Convert.ToInt32 (snstring [+ 1])' не могут быть преобразованы в уголь, как это выходит за пределы диапазона. Смирись с этим. –

+0

Остановить преобразование между 'int' и' char'. Преобразуйте в 'int' один раз, примените все биты, а затем конвертируйте обратно. – Phylogenesis

+0

Почему бы не использовать хорошую старую функцию c? См .: http://stackoverflow.com/a/11593657/3989673 – bigahega

ответ

1

Я выполнил аналогичную задачу, то есть взять номер в качестве ввода и выполнить именно то, что делает ваш код на C#. Я беру строку как входную и возвращающую строку. Ниже приведен код:

private string ComputeKey(string serialnumber) 
     { 
      if (string.IsNullOrEmpty(serialnumber)) 
      { 
       throw new Exception("Cannot generate a key from a null or empty string"); 
      } 

      serialnumber += '\0'; 
      var length = serialnumber.Length; 
      byte[] snbytes = Encoding.UTF8.GetBytes(serialnumber); 
      for (int i = 0; i < length - 1; i++) 
      { 
       snbytes[i + 1] -= 0x30; 
       snbytes[i] = (byte)~snbytes[i + 1]; 
       snbytes[i] &= 0x07; 
      } 
      snbytes[length - 1] <<= 1; 
      snbytes[length - 1] &= 0x07; 

      var sb = new StringBuilder(); 
      for (int j = 0; j < length - 1; j++) 
      { 
       sb.Append(snbytes[j].ToString()); 
      } 

      return sb.ToString(); 
     } 
1

Когда вы переворачиваете биты 32-разрядного int, представляющего char, который всегда имеет один байт в C, вы получаете верхние три байта, установленные на 0xFF. Однако C счастливо отбивает верхние байты при назначении char, а конвертер C# генерирует исключение.

Вы можете исправить это с помощью бросания вместо преобразования соответствует тому, что делает C:

snstring[i+1] -= '0'; 
snstring[i] = (char)(~snstring[i+1] & 0x07); 

По существу, литой говорит C# явно делать то же самое, что C делает по умолчанию.

+1

. В итоге вы получаете верхние байты, установленные в 0xFF, в C, из-за цельной рекламы. Но C является слабым и позволяет присваиванию выполнять неявное преобразование обратно в тип lvalue сразу после, без каких-либо диагностических операций. Проще говоря, прочный C-код также должен делать неявный приведение к предполагаемому типу непосредственно после '~', например '(unsigned char) ~ snstring [i + 1]'. (Вы не хотите использовать 'char' для этого в C, потому что он имеет плохо определенную подпись.) – Lundin

+0

Исправлено, спасибо! – dasblinkenlight