Objective-c负十六进制值

时间:2014-12-12 22:06:44

标签: ios objective-c hex nsdata

我在NSData上有以下类别方法。我尝试在给定索引处提取位字段并将其作为NSNumber返回。我让它完美地为所有积极工作,但我需要它与负数一起工作。

我的实施如下:

#import <Foundation/Foundation.h>
@interface NSData (ExternalDevices)
@end
@implementation NSData (ExternalDevices)
- (NSNumber *)extractLittleEndianBitFieldAtIndex:(int)index forLength:(int)length
{

    //This function has limitations on the "length" parameter that are not yet know/defined
    //These limitations are due to the max size of "NSInteger intData" defined below

    int first_byte = index/8;                             //Index of the first byte containing this bit field
    int last_byte = (length+index-1)/8;                          //Index of the last byte containing this bit field
    int byte_length = last_byte - first_byte + 1;                   //number of bytes containing this bit field

    Byte *byteArray = (Byte*)malloc(byte_length);
    memcpy(byteArray, [[self subdataWithRange:NSMakeRange(first_byte, byte_length)] bytes], byte_length);

    NSInteger intData = *((NSInteger *)byteArray);

    free(byteArray);
    return [NSNumber numberWithInt:intData];
}

+ (NSData *)dataFromHexString:(NSString *)string
{
    string = [string lowercaseString];
    NSMutableData *data= [NSMutableData new];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i = 0;
    NSUInteger length = string.length;
    while (i < length-1) {
        char c = [string characterAtIndex:i++];
        if (c < '0' || (c > '9' && c < 'a') || c > 'f')
            continue;
        byte_chars[0] = c;
        byte_chars[1] = [string characterAtIndex:i++];
        whole_byte = strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];

    }

    return data;
}
@end



@interface Testing:NSObject
@end
@implementation Testing


- (instancetype)init
{
    self = [super init];
    if (self)
    {
        {
            NSData *data = [NSData dataFromHexString:@"e30b"];
            NSLog(@"%@ should be 3043", [data extractLittleEndianBitFieldAtIndex:0 forLength:16]);
        }

        {
            NSData *data = [NSData dataFromHexString:@"46e0"];
            NSLog(@"%@ should be -8122", [data extractLittleEndianBitFieldAtIndex:0 forLength:16]);
        }

        {
            NSData *data = [NSData dataFromHexString:@"f208"];
            NSLog(@"%@ should be 2290", [data extractLittleEndianBitFieldAtIndex:0 forLength:16]);
        }

        {
            NSData *data = [NSData dataFromHexString:@"10e6"];
            NSLog(@"%@ should be -6640", [data extractLittleEndianBitFieldAtIndex:0 forLength:16]);
        }

        {
            NSData *data = [NSData dataFromHexString:@"018900"];
            NSLog(@"%@ should be 137", [data extractLittleEndianBitFieldAtIndex:8 forLength:16]);
        }
    }
    return self;
}

@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        [[Testing alloc] init];
    }
}

以下网站似乎总能在INT16下产生我想要的结果 - Little Endian(BA)

http://www.scadacore.com/field-applications/miscellaneous/online-hex-converter.html

虽然重要的是要注意并非我使用的每个号码都是INT16

1 个答案:

答案 0 :(得分:1)

你的专栏:

NSInteger intData = *((NSInteger *)byteArray);

是您的关键问题,原因有两个:

  1. byteArray可能比NSInteger更短(或更不可能,更长),您最终会阅读垃圾。例如。如果你的例子中byteArray是2个字节,NSInteger是4个字节 - 它将是64位 - 你将读取两个字节的垃圾。

  2. 如果要转换有符号值,则需要对值进行符号扩展 - 即将符号位复制到较高的未使用位。例如。如果要将带符号的16位字段转换为32位有符号值,则高16位需要复制16位值的最高有效位,因此0x7000 - &gt; 0x00007000和0x8000 - &gt; 0xFFFF8000。

  3. 您需要提出一种处理这些问题的算法。您可能会发现使用屏蔽(和'),或者“移动”来转换一个字节更容易。

    HTH