2013-09-19 6 views
1

При попытке дублировать PHP bin2hex($s) и pack('H*',$s) (aka hex2bin($s) в PHP 5.4.3+) в GCC/Linux C++ я, похоже, понял это, за исключением того, что он помечает пунктуацию по какой-то странной причине. Можете ли вы выяснить, что я могу сделать неправильно в функции hex2bin()? Я сравнивал bin2hex() с моим и, похоже, работает там правильно, поэтому проблема в hex2bin().Отсутствие пунктуации из C++ hex2bin

#include <strings.h> 
#include <string> 
#include <stdio.h> 
#include <stdlib.h> 
using namespace std; 

string bin2hex(string s) { 
    int nLen = s.length(); 
    string sOut; 
    char cBuff[2]; 
    for (int i = 0; i < nLen; i++) { 
    sprintf(cBuff,"%.2x",s[i]); 
    sOut.append(cBuff); 
    cBuff[0] = '\0'; 
    } 
    return sOut; 
} 

string hex2bin(string s) { 
    int nLen = s.length(); 
    string sOut; 
    char cBuff1[2]; 
    char cBuff2[2]; 
    char cBuff[1]; 
    int n,n1,n2; 
    for (int i = 0; i <= nLen; i+=2) { 
    sprintf(cBuff1,"%c",s[i]); 
    sprintf(cBuff2,"%c",s[i+1]); 
    n1 = atoi(cBuff1); 
    n2 = atoi(cBuff2); 
    n = (n1 * 16) + n2; 
    sprintf(cBuff,"%c",n); 
    sOut.append(cBuff); 
    cBuff[0] = '\0'; 
    cBuff1[0] = '\0'; 
    cBuff2[0] = '\0'; 
    } 
    return sOut; 
} 

int main() { 
    string s; 
    string sResult; 
    s = "This is a 123 test."; 
    sResult = bin2hex(s); 
    printf("ENCODED: %s\n",sResult.c_str()); 
    sResult = hex2bin(sResult); 
    printf("UNENCODED: %s\n",sResult.c_str()); 
    return 1; 
} 

Срабатывает:

ENCODED: 5468697320697320612031323320746573742e 
UNENCODED: This is a 123 test 
+1

Это ... довольно тревожный код. Также: hex is _encoding_ *** not *** _encryption_. Надеюсь, вы знаете разницу. (!?!?). (Я взял на себя смелость переписать это в реализацию на C++. См. Мой ответ) – sehe

+1

Что вы ожидали от n2 = atoi (cBuff2); делать, когда это доходит до этого «e» в конце вашего ввода? Он вернет 0 и n будет 2 * 16 + 0 = 32, которое является пространством. Я не думаю, что вы можете использовать atoi - вам нужно что-то, что может принять radix af 16. strtol, вероятно, сработает. И, возможно, sscanf. –

+0

@sehe Посмотрите меня на Twitter и давайте подключаться по электронной почте. Я пересматриваю C++, не касаясь его в течение 20 лет. Ваша обратная связь оправдана, и любые подробные отзывы о том, как я могу лучше кода на этой платформе, оцениваются. Например, я даже не сосредоточился на утечке памяти, потому что я не знаю, как правильно освободить материал. – Volomike

ответ

4

Хорошо, засучив рукава: давайте посмотрим на C++ версии:

Live on Coliru

  • Не используйте строки C, если не нужно (sprintf для создания строки с двумя символами не является ... очень эффективным)
  • Используйте iostreams для кодирования/декодирования шестнадцатеричных цифр (std::hex)
  • hex2bin может оптимизировать, но я пошел на "проще"
  • Я добавил капельку ввода дезинфицирующей на hex2bin
#include <string> 
#include <sstream> 
#include <iomanip> 

std::string bin2hex(std::string const &s) { 
    std::ostringstream oss; 

    for (auto ch : s) 
     oss << std::hex << std::setw(2) << std::setfill('0') << (int) ch; 

    return oss.str(); 
} 

#include <cassert> 
std::string hex2bin(std::string const& s) { 
    assert(s.length() % 2 == 0); 

    std::string sOut; 
    sOut.reserve(s.length()/2); 

    std::string extract; 
    for (std::string::const_iterator pos = s.begin(); pos<s.end(); pos += 2) 
    { 
     extract.assign(pos, pos+2); 
     sOut.push_back(std::stoi(extract, nullptr, 16)); 
    } 
    return sOut; 
} 

#include <iostream> 
int main() { 
    std::cout << "ENCODED: " << bin2hex("This is a 123 test.")   << "\n"; 
    std::cout << "DECODED: " << hex2bin(bin2hex("This is a 123 test.")) << "\n"; 
} 

Выход:

ENCODED: 5468697320697320612031323320746573742e 
DECODED: This is a 123 test. 
+0

далее улучшено, чтобы использовать 'std :: stoi' вместо' istringstream' в 'hex2bin' – sehe

+0

My G ++ дает мне ошибку для автоматической строки в bin2hex. В нем говорится: 'error: ожидаемый инициализатор до ':' токен' – Volomike

+0

Я переключил значение for в bin2hex на' for (int i = 0; i Volomike

1

Ваш код не преобразует шестнадцатеричные цифры правильно, потому что atoi может обрабатывать только десятичных цифр. Попробуйте

sprintf(cBuff1,"%c",s[i]); 
sprintf(cBuff2,"%c",s[i+1]); 
n1 = strtoul(cBuff1, 0, 16); 
n2 = strtoul(cBuff2, 0, 16); 

Кроме того, ваш цикл должен быть

for (int i = 0; i < nLen; i+=2) { 
1
n1 = atoi(cBuff1); 
n2 = atoi(cBuff2); 
n = (n1 * 16) + n2; 

если cbuff1 есть, скажем, "a", то это не будет работать, так как a это не цифра. Он отлично работает для цифр, которые являются «0-9», но не «a-f».

Вам нужно будет перевести цифры без цифр в числовые значения.

Существует довольно много способов преобразования строки шестнадцатеричного значения в байт. Я думаю, что это довольно приличный:

int hexchar(char c) 
{ 
    if (c >= '0' && c <= '9') return c - '0'; 
    // if you need to support upper-case hex: 
    // c = tolower(c); 
    if (c >= 'a' && c <= 'f') return c - 'a' + 10; 
    // If we get here, panic 
    cout << "Error, invalid hex digit:" << c << endl; 
    return -1; 
} 

int hexbyte(string s) 
{ 
    for(i = 0; i < s.length(); i+=2) 
    { 
     char c = hexbyte(s[i]); 
     c <<= 4; 
     c += hexbyte(s[i+1]; 
     cout << c; 
    } 
} 
2

со всеми но период '.' вам просто повезло: шестнадцатеричные цифры не использовали фактический шестнадцатеричный val уе. Однако за период, который вы получили 2e, но вы попытались декодировать e, используя atoi("e"), примерно: это не сработает atoi() требует десятичного значения. Вместо этого вы можете использовать strtol(str, 0, 16), чтобы декодировать шестнадцатеричное значение.

Обратите внимание, что при использовании sprintf() у вас есть несколько переполнений буфера: эта функция записывает завершающий нулевой символ. В общем, вам намного лучше до snprintf(), чтобы избежать переполнения буфера.Кроме того, в вашей процедуре декодирования вы получаете доступ к значениям за пределами строки (вы используете i <= nLen с nLen = s.length(), а затем получаете доступ к s[i] и s[i+1]). Конечно, код слишком сложный:

#include <string> 
#include <sstream> 
#include <iostream> 
#include <iomanip> 

std::string bin2hex(std::string s) { 
    std::ostringstream out; 
    out << std::hex << std::setfill('0'); 
    for (char c: s) { 
     out << std::setw(2) << int(c); 
    } 
    return out.str(); 
} 

std::string hex2bin(std::string s) { 
    std::string rc; 
    int nLen = s.length(); 
    int tmp; 
    for (int i(0); i + 1 < nLen; i += 2) { 
     if (std::istringstream(s.substr(i, 2)) >> std::hex >> tmp) { 
      rc.push_back(tmp); 
     } 
    } 
    return rc; 
} 

int main() { 
    std::string s; 
    std::string sResult; 
    s = "This is a 123 test."; 
    sResult = bin2hex(s); 
    std::cout << "ENCRYPTED: " << sResult << '\n'; 
    sResult = hex2bin(sResult); 
    std::cout << "UNENCRYPTED: " << sResult << '\n'; 
    return 1; 
} 
+0

O hey, +1, еще одно верное предложение iostreams. Я немного разочарован тем, что вы оставили неверные слова 'ENCRYPTED' и' UNENCRYPTED' (_sic_), хотя: / – sehe

Смежные вопросы