2016-07-13 11 views
0

unsigned longをソケット経由で送信する必要があります。 unsigned longが4バイトであるため、受信側は4バイトしか期待していません。私が書いた変換関数は以下のようなものですが、charに格納しなければならない数値が127以下でなければなりません。 0x7F。 0x7fより大きい値の場合、拡張ASCIIテーブル(http://www.asciitable.com/)に従った文字がcharに格納されると予想しますが、それは間違いありません。 0x90の場合、何も格納されません。私はUnicode文字セットでVS12を使用しています。C++で符号なしlongをchar *に変換する最も良い方法は

どのような変換方法が正しいですか?

void number2char(unsigned long number, char* nrAsByte){ 
    std::stringstream numberSS; 
    numberSS << std::hex << number; 
    int length = numberSS.str().length(); 
    length = length/2.0 + 0.5; 
    nrAsByte = new char[sizeof(number)](); 
    std::fill(nrAsByte, nrAsByte + length, '\x20'); 
    while (length > 0){ 
     int lastTwo = (number & 0xff); 
     number >>= 8; 
     unsigned char a = lastTwo; // this doesn't work if lastTwo > 0x7F 
     std::memcpy(nrAsByte + length - 1, &a, 1); 
     --length; 
    } 
} 

私はコードのために申し訳ありませんが、それはよく私がテストされていなかった、それはバグを含んだ、ITを使用しないでください、代わりに答えをアドバイスに従ってください

+5

なぜ4バイトを直接送信しないのですか? – Mine

+0

どうしたらうまくいかないのですか? – immibis

+0

投稿した機能がメモリをリークします。メモリは 'nrAsByte'に割り当てられますが、呼び出し元がメモリへのポインタを取得する仕組みはありません。基本的には変換をしようとしているようですが、結果は呼び出し元に転送されません... – skyking

答えて

2

なぜありません以下のようなもの:それは完全で正しい感じていなかった、そして最後に、私は私が予想以上に複雑なもので終わったよう

void number2char(unsigned long number, char* nrAsByte){ 
    unsigned char *dst= reinterpret_cast<unsigned char *> nrAsByte; 
    for (int i=0; i<sizeof(unsigned long); ++i) { 
     *dst++= number & 0xFF; 
     number >>= 8; 
    } 
} 
0

フム、私は、アントニオの答えと周りいじるしてきたが、複雑です、それを持っています時々目的。 (それは、htonlでこれを混ぜるのいずれかにこれを使用するか、またはhtonlでそれを書き換えることは望ましくないですので、多分反対のエンディアンで)

次のコードは、手動で他のものの間でもhtonl/ntohl様変換を行っています。

アントニオのソースとは異なり、入力番号タイプは8バイト長であるとき、それはメモリを上書きしません(unsigned longは私のテストplatformに8バイトです - ところで、それを試してみてください!)、それが代わりに希望に合わせて値が切り捨てられますネットワークchar *バッファ

基本的にはunsigned int number(char *)(&number)として使用していますが、エンディアンを守ることはできませんが、メモリを上書きしてしまう可能性があります。あなたは異なる長さのタイプを混ぜる)。しかし、不明な点がある場合は何でも尋ねてください。

#include <iostream> 
#include <string> 

// Experiment with different types to see differences 
// (and how data are truncated when sizeof number > sizeof networkdata) 

//typedef unsigned int numberType_t; 
typedef unsigned long numberType_t; // on my platform this is 8 bytes long 

constexpr int networkBytesSize = 4; // number of chars to be sent trough network with (char *) 
// define network data type: 
// used "struct" to make sizeof(networkData_t) return actual number of bytes 
typedef struct { 
    unsigned char d[networkBytesSize]; 
    char *cptr() { return reinterpret_cast<char *>(d); } 
} networkData_t; 

// Writes number into network char* buffer nrAsByte, endianness agnostic 
void number2char(numberType_t number, networkData_t & nrAsByte) { 
    for (size_t i = 0; i < sizeof(networkData_t); ++i) { 
     nrAsByte.d[i] = number & 0xFF; 
     number >>= 8; 
    } 
} 

// Read number back from network char* buffer 
numberType_t char2number(const networkData_t & nrAsByte) { 
    numberType_t number = 0; 
    size_t i = sizeof(networkData_t); 
    while (i--) number = (number<<8) | nrAsByte.d[i]; 
    return number; 
} 

int main() 
{ 
    printf("numberType_t size in bytes: %lu, networkData_t size in bytes: %lu\nAll following numbers are hex:\n", 
      sizeof(numberType_t), sizeof(networkData_t)); 

    numberType_t number = numberType_t(0x9ABCDEFFEul); 
    std::cout << "source number: " << std::hex << number << std::endl; 

    // Write number into char buffer 
    networkData_t networkData; 
    number2char(number, networkData); 
    std::cout << "network bytes:"; 
    for (size_t i = 0; i < sizeof(networkData_t); ++i) std::cout << " [" << unsigned(networkData.d[i]) << "]"; 
    std::cout << std::endl; 

    // Test usability of (char *) pointer access 
    const char * testCharPtrConversion = networkData.cptr(); 
    printf("as char * (decimal signed): %d %d ...\n", testCharPtrConversion[0], testCharPtrConversion[1]); 

    // Read number from char buffer 
    number = char2number(networkData); 
    std::cout << "read number: 0x" << std::hex << number << std::endl; 
} 
+0

そしておそらく私は 'char *'をnetworkData_tに変換する方法を示していたはずです... networkData_tを普通のC++構造体に2つのコンストラクタを使って変更するのはおそらく最も簡単でクリーンです:http://cpp.sh/3gvoこのような短期間にいくつの間違いが起きたか心配しているので、これらをまとめてフル・クラスを構築し、すべてが期待どおりに動作するかどうかを検証するための徹底した単体テストを書くことを強くお勧めします。 – Ped7g

+1

AFAIK htonlはビッグエンディアンに変換されますが、あなたのコードはリトルエンディアンに変換されます(最下位4桁のオクテットのみ)。 –

+0

@Bob__まあ、私は "htonlに似ている"と言っていましたが、それが正確かどうか気にしなかったので、正しいかもしれません。それをキャッチしてくれてありがとう。私は文言を編集して、それが代替語ではなく代替語であることを示します(両端でエンディアンがどのように解決されるかを示すために)。 – Ped7g

関連する問題