将整数打包为字节(NSData)

发布于 2024-09-18 08:33:47 字数 1039 浏览 5 评论 0原文

我想将 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]);
}

执行此操作并且它会起作用,但我希望解决方案能够获得NSData 只有 3 个字节。

I want to pack a MIDI message into an NSData object.

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);

This works wonderfully and while I'm proud of myself, I know that the conversion to bytes is not done correctly: it should be a direct conversion without a lot of addition and multiplication. How can that be done?

Edit: I'm now aware that I can just do this

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

and on the Java side

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

and it will work, but I'd like the solution to get an NSData with just 3 bytes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

相对绾红妆 2024-09-25 08:33:47

就我个人而言,我会选择 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];

Personally, I would go for an NSString:

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

Easy to use, and easy to transfer. Unpacking is a tiny bit more complicated, but not difficult at all either.

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];
过度放纵 2024-09-25 08:33:47

这是我整理的一个 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端都试过了,都没有问题。 字节顺序没有问题,因为每个整数都适合一个字节(或者在一种情况下两个整数适合一个字节)。

Here's a 3-byte solution that I put together.

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);

and on the other side of the wire, this is just as easy to pick up, because each byte is a byte. I just finished trying this on the iOS side and the Java side, and there are no problems on either. There is no problem with endian-ness, because each integer fits into one single byte (or two in one byte, in one case).

木森分化 2024-09-25 08:33:47

你有几种选择。

因为看起来您想要 NSData 表示中的连续数据团...

您需要创建一个打包结构,并将数据作为预定义的字节顺序传递给 NSData 调用(因此两端都知道如何取消存档数据全局)。

/* 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:©.glob length:sizeof(copy.glob)]);
    assert(packedData);

    t_midi_message_archive recovered;
    [packedData getBytes:&recovered.glob];

    recovered.swapToNativeEndianFromTransferEndian();
    /* recovered may now be used safely */
}

you have several options.

since it looks like you want a contiguous glob of data in the NSData representation...

you'll want to create a packed struct, and pass the data to the NSData call as a predefined endianness (so both ends know how to unarchive the data 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:©.glob length:sizeof(copy.glob)]);
    assert(packedData);

    t_midi_message_archive recovered;
    [packedData getBytes:&recovered.glob];

    recovered.swapToNativeEndianFromTransferEndian();
    /* recovered may now be used safely */
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文