I need to add CRC calculation to my app and found Apple's sample ZipBrowser project. This project uses the CRC function inside zlib.h:
#import <zlib.h>
static inline uint32_t _crcFromData(NSData *data) {
uint32_t crc = crc32(0, NULL, 0);
return crc32(crc, [data bytes], [data length]);
}
(Because I don't really understand the significance of static inline
) I thought I'd make the function look like a typical Objective-C method:
- (uint32_t)_crcFromData:(NSData *)data
{
uint32_t crc = crc32(0, NULL, 0);
return crc32(crc, [data bytes], [data length]);
}
This produces different answers from static inline
! Why is that?
In addition, both give me "Implicit conversion loses integer precision" compiler warnings.
Next, I cast crc32
and [data length]
(e.g. return (uint32_t)crc32...
). The compiler warnings went away of course but the return values are still different from static inline
.
I removed the casts again because I'm not sure if the CRC will be sensitive to changes in width of the variables I'm using (so it now looks exactly like the code pasted above).
(Using NSLog
, it seems that the difference occurs when I call crc32(crc, [data bytes], [data length]);
not when I return the value from static inline
function or Obj-C method. In other words, it seems to make a difference where you call the zlib function from.)
Next, I found sample code for adding a CRC algorithm as an NSData
category and I used this code to compare answers against my zlib calls. Comparing 3 approaches, I get different results depending on what data I pass in (sometimes 2 will match but not always the same 2)!
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSFileHandle *fileHandle = [NSFileHandle
fileHandleForReadingAtPath:@"/Users/steve/Music/iTunes/iTunes Music/pops1/001.mp3"];
NSLog(@"Cocoa style declaration: %u", [self _crcFromData:[fileHandle readDataOfLength:1024]]); //returns: 3157848792
NSLog(@"Static inline declaration: %u", _crcFromData([fileHandle readDataOfLength:1024])); //returns: 4021661486
NSLog(@"Self-coded CRC: %u", [[fileHandle readDataOfLength:1024] crc32]); //returns: 4021661486
NSLog(@"Cocoa style declaration: %u", [self _crcFromData:[fileHandle readDataOfLength:500]]); //returns: 42187130
NSLog(@"Static inline declaration: %u", _crcFromData([fileHandle readDataOfLength:500])); //retu开发者_如何学Gorns: 42187130
NSLog(@"Self-coded CRC: %u", [[fileHandle readDataOfLength:500] crc32]); //returns: 4168292535
NSLog(@"Cocoa style declaration: %u", [self _crcFromData:[fileHandle readDataOfLength:5000]]); //returns: 2401083626
NSLog(@"Static inline declaration: %u", _crcFromData([fileHandle readDataOfLength:5000])); //returns: 3786034839
NSLog(@"Self-coded CRC: %u", [[fileHandle readDataOfLength:5000] crc32]); //returns: 2526276347
}
Given the different answers, I assume that the safest approach is the static inline
approach used in the Apple sample project.
Wrapping this into more specific questions:
- What are the
static inline
and the Objective-C versions doing differently that causes them to receive different values fromCRC32
? - What is the best way to avoid the compiler errors? Use different data types (that don't affect the result of the CRC calculation)? Or suppress compiler warnings?
- If I should just suppress compiler warnings, I would want to do it on just the file. I've found articles (e.g. http://joshua.nozzi.name/2011/03/per-file-compiler-flags-in-xcode-4/) on where to make the setting but no article on how to make the setting. I've seen long lists of flags such as
Wpadded
,Wlong-long
,Werror
, etc but nothing that tells me which is the one I need, and how to actually set it as plain text inside the per-file setting in Xcode 4 (e.g.Wconversion=
something?). - Finally, and more to the point, which is the correct approach? It shouldn't be possible to have different CRC values otherwise this defeats the whole purpose of CRC!
Sorry about the roundabout way I've asked this question but I'm trying to give a bigger picture of my problem in case I've made some basic wrong assumption along the way resulting in me asking the wrong questions. Thank you.
UPDATE
The sample project compiles perfectly but when I paste this code into my own project I get the compiler warnings. It seems that this is because that project has "Implicit conversion to 32 Bit Type" in Build Settings set to "Yes". As this is project-wide, I think it would be better not to use this in my own app if I can do it per-file.
精彩评论