如何在 Objective-C 中对 NSData 进行按位异或?

Posted

技术标签:

【中文标题】如何在 Objective-C 中对 NSData 进行按位异或?【英文标题】:How do I do a bit-wise XOR on NSData in Objective-C? 【发布时间】:2015-04-28 01:45:20 【问题描述】:

我有两个 NSData 对象 data1 和 data2,我想做一个按位异或并将结果存储在第三个 NSData 对象 xorData 中。

我尝试的第一件事是:

*data1.bytes^*data2.bytes;

但它给出了一个错误:

二进制表达式的无效操作数('const void' 和 'const void')

所以我尝试编写一个函数,将数据的字节提取到整数数组中,对整数执行异或,然后将结果保存回 NSData 对象。函数如下所示:

+(NSData *) DataXOR1:(NSData *) data1
DataXOR2:(NSData *)data2
    const int *data1Bytes = [data1 bytes];
    const int *data2Bytes = [data2 bytes];
    NSMutableArray *xorBytes = [[NSMutableArray alloc] init ];
    for (int i = 0; i < data1.length;i++)
         [xorBytes addObject:[NSNumber numberWithInt:(data1Bytes[i]^data2Bytes[i])]];
    
    NSData *xorData = [NSKeyedArchiver archivedDataWithRootObject:xorBytes];
    return xorData;

这运行,但给出了错误的答案。当我在两个简单的数据(data1 = 0x7038 和 data2 = 0x0038)上测试它并使用 NSLog 输出值是什么时,我得到:

data1Bytes[0] = 8070450532247943280
data2Bytes[0] = 8070450532247943168
data1Bytes[0]^data2Bytes[0] = 112
data1Bytes[1] = 10376302331560798334
data2Bytes[1] = 10376302331560798334
data1Bytes[1]^data2Bytes[1] = 0

这让我有点不知所措,因为 dataXBytes 数组中的值完全错误,但它们与正确的值异或! (0x70 ^ 0x00 = 0x70 = 112)

我认为这可能是字节序问题,但是当我将 data1Bytes 的初始化更改为:

const int *data1Bytes = CFSwapInt32BigToHost([data1 bytes]);

它在尝试访问它时遇到错误,说:

线程 1:EXC_BAD_ACCESS(code=1, address = 0xa08ad539)

有没有更简单的方法来做异或?如果没有,我该如何解决字节序问题?

【问题讨论】:

如果您从 NSData 对象中获取字节数组,为什么将它们声明为 int 数组? (这只是你的问题之一。) 仅供参考,8070450532247943280 = 0x7000000000003870。和8070450532247943168 = 0x7000000000003800。所以 xor 对我来说看起来不错。正如 Hot Licks 所暗示的,问题在于您正在使用 int * 指针并获得 64 位数字。底层数据是什么?您是否有理由不使用更能代表字节的东西(例如uint8_t)?你到底想做什么?您没有向我们展示 NSData 对象中的内容,因此我们很难提供建议。 【参考方案1】:

投射到int 然后归档NSNumbers 的NSArray 肯定不会产生您正在寻找的结果。你会想要一些可变的NSData 来附加各个字节,比如

+(NSData *) DataXOR1:(NSData *) data1
            DataXOR2:(NSData *)data2
    const char *data1Bytes = [data1 bytes];
    const char *data2Bytes = [data2 bytes];
    // Mutable data that individual xor'd bytes will be added to
    NSMutableData *xorData = [[NSMutableData alloc] init];
    for (int i = 0; i < data1.length; i++)
        const char xorByte = data1Bytes[i] ^ data2Bytes[i];
        [xorData appendBytes:&xorByte length:1];
    
    return xorData;

【讨论】:

谢谢,这完美!不过,如果您不介意回答两个问题: 1) 为什么 char 是指向通用数据字节的最佳选择? 2)据我了解,循环在每次迭代中初始化变量“xorByte”,以便它将在内存中为数据分配一个点,然后“appendBytes:&xorByte”使 xorData 指向所有这些新变量。对吗? (1) char 保证实际上是一个字节,而 int 不是。 (2) xorByte 是一个堆栈变量,它在每个循环中进出堆栈内存(尽管可能有一个优化使它的寿命更长),对-appendBytes:length: 的调用实际上是副本 i> 将xorByte 的值转化为xorData 的内部数据。【参考方案2】:
+ (NSData *) xorData:(NSData *)data1 with:(NSData *)data2

    // make data1 smaller
    if (data1.length > data2.length) 
        NSData *t = data1;
        data1 = data2;
        data2 = t;
    

    char *xor = (char *) malloc(data2.length * sizeof(char));
    char * data1Bytes = (char *) data1.bytes;
    char * data2Bytes = (char *) data2.bytes;

    for (int i = 0; i <data1.length; i++)
    
        xor[i] = data1Bytes[i] ^ data2Bytes[i];
    

    NSMutableData *data = [[[NSMutableData alloc] initWithBytes:xor length:data1.length] autorelease];
    [data appendData:[data2 subdataWithRange:NSMakeRange(data1.length, data2.length - data1.length)]];
    free(xor);
    return [NSData dataWithData:data];

【讨论】:

1.不要转换malloc 的结果。 2. 首先为什么要使用malloc?请改用NSMutableData 并避免复制。 3. 不要再进行不必要的复制(在最后一行)。 我想返回 NSData,而不是 NSMutableData,那么最好的方法是什么? 返回(非可变)NSData 有什么意义?该实例是在您的本地源代码中创建的,而不是共享或存储的。方法返回后不能对其进行变异。调用者无法区分可变实例和非可变副本。 最佳实践。 “方法返回后不能变异。” > 你确定吗?我不这么认为。如果转换为 NSMutableData,则返回值可能会发生变化,因为原始指针是可变对象。 没错,调用者可以做到这一点。但这将是调用者的(错误)决定。调用者当然不应该这样做,因为这意味着依赖 xor 方法的实现细节。 xor 方法不应该担心外部代码可能会滥用其返回值。

以上是关于如何在 Objective-C 中对 NSData 进行按位异或?的主要内容,如果未能解决你的问题,请参考以下文章

objective-c如何将文件中内容转化为NSData

Objective-C NSData/NSMutableData

将 NSData Objective-C 代码转换为 Swift 时遇到问题

Objective-C:以编程方式单击网站按钮

如何将 NSData 参数传递给在 swift 3 中调用的目标 c 方法?

NSArray怎么转换为NSData