代码之家  ›  专栏  ›  技术社区  ›  Dan Rosenstark

将整数打包为字节(nsdata)

  •  4
  • Dan Rosenstark  · 技术社区  · 14 年前

    我想将一条MIDI消息打包到一个nsdata对象中。

    int messageType = 3; // 0-15
    int channel = 5;      // 0-15
    int data1 = 56;       // 0-127
    int data2 = 78;       // 0-127
    
    int packed = data2;
    packed += data1 * 127;
    packed += channel * 16129; // 127^2
    packed += messageType * 258064; // 127^2 * 16
    
    NSLog(@"packed %d", packed);
    
    NSData *packedData = [NSData dataWithBytes:&packed length:sizeof(packed)];
    
    int recovered;
    [packedData getBytes:&recovered];
    
    NSLog(@"recovered %d", recovered);
    

    这工作得很好,虽然我为自己感到自豪,但我知道字节转换没有正确完成: 它应该是一个没有很多加法和乘法的直接转换。怎么能做到?

    编辑: 我现在知道我可以做这个了

    char theBytes[] = {messageType, channel, data1, data2};
    NSData *packedData = [NSData dataWithBytes:&theBytes length:sizeof(theBytes)];
    

    在Java方面

    byte[] byteBuffer = new byte[4]; // Receive buffer
    while (in.read(byteBuffer) != -1) {  
        System.out.println("data2="  + byteBuffer[3]);
    }
    

    它可以工作,但是我希望这个解决方案能得到一个只有3个字节的nsdata。

    3 回复  |  直到 12 年前
        1
  •  3
  •   Dan Rosenstark    14 年前

    就我个人而言,我会选择一个nsstring:

    NSString *dataString = [NSString stringWithFormat:@"%i+%i+%i+%i", messageType, channel, data1, data2];
    NSData *packedData = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    

    使用方便,易于转移。解包有点复杂,但也不难。

    NSScanner *scanner = [NSScanner scannerWithString:[[[NSString alloc] initWithData:packedData encoding:NSUTF8StringEncoding] autorelease]];
    int messageType, channel, data1, data2;
    [scanner scanInt:&messageType];
    [scanner scanInt:&channel];
    [scanner scanInt:&data1];
    [scanner scanInt:&data2];
    
        2
  •  2
  •   Dan Rosenstark    14 年前

    这里有一个3字节的解决方案。

    char theBytes[] = {message_type  * 16 + channel, data1, data2};
    NSData *packedData = [NSData dataWithBytes:&theBytes length:sizeof(theBytes)];
    
    char theBytesRecovered[3];
    [packedData getBytes:theBytesRecovered];
    
    int messageTypeAgain = (int)theBytesRecovered[0]/16;
    int channelAgain = (int)theBytesRecovered[0] % 16;
    int data1Again = (int)theBytesRecovered[1];
    int data2Again = (int)theBytesRecovered[2];
    
    NSLog(@"packed %d %d %d %d", messageTypeAgain, channelAgain, data1Again, data2Again);
    

    而在电线的另一边,这同样容易理解,因为每个字节都是一个字节。我刚刚在iOS端和Java端完成了这一尝试,而且也没有问题。 尾数不存在问题,因为每个整数只能容纳一个单字节(在一种情况下,一个字节可以容纳两个)。

        3
  •  0
  •   justin    14 年前

    你有几个选择。

    因为看起来您希望在nsdata表示中有一个连续的数据球…

    您需要创建一个打包的结构,并将数据作为一个预定义的endianness传递给nsdata调用(这样,两端都知道如何取消对数据glob的归档)。

    /* pack this struct's ivars and and enable -Wreorder to sanity check that the compiler does not reorder members -- i see no reason for the compiler to do this since the fields are equal size/type */
    struct t_midi_message {
        UInt8 message_type; /* 0-15 */
        UInt8 channel; /* 0-15 */
        UInt8 data1; /* 0-127 */
        UInt8 data2; /* 0-127 */
    };
    
    union t_midi_message_archive {
    /* members - as a union for easy endian swapping */
        SInt32 glob;
        t_midi_message message;
        enum { ValidateSize = 1 / (4 == sizeof(t_midi_message)) };
    /* nothing unusual here, although you may want a ctor which takes NSData as an argument */
        t_midi_message_archive();
        t_midi_message_archive(const t_midi_message&);
        t_midi_message_archive(const t_midi_message_archive&);
        t_midi_message_archive& operator=(const t_midi_message_archive&);
    
    /* swap routines -- just pass @member glob to the system's endian routines */
        void swapToNativeEndianFromTransferEndian();
        void swapToTransferEndianFromNativeEndian();
    
    };
    
    void a(const t_midi_message_archive& msg) {
    
        t_midi_message_archive copy(msg);
        copy.swapToTransferEndianFromNativeEndian();
    
        NSData * packedData([NSData dataWithBytes:&copy.glob length:sizeof(copy.glob)]);
        assert(packedData);
    
        t_midi_message_archive recovered;
        [packedData getBytes:&recovered.glob];
    
        recovered.swapToNativeEndianFromTransferEndian();
        /* recovered may now be used safely */
    }