[精通Objective-C] 使用自定义下标模拟32位计算机寄存器操作
参考书籍:《精通Objective-C》【美】 Keith Lee
目录
程序功能简介
创建一个命令行程序用于模拟32位计算机的寄存器操作。它可以设置和获取寄存器的内容。该程序含有3个命令行输入参数:寄存器的初始化设置(32位的十六进制值)、选中的用于执行获取/设置操作的寄存器字节,以及(可选的)用于设置的寄存器字节值(十六进制)。
寄存器类
首先创建一个用于存放寄存器常量的头文件RegEditConstants.h
#ifndef RegEditConstants_h
#define RegEditConstants_h
#define kByteMultiplier 0xFF // 用于辅助执行寄存器的位操作
#define kRegisterSize (sizeof(uint32)) // 寄存器的宽度(以位为单位)
#endif
接下来是模拟寄存器操作的RegEdit类:
#import <Foundation/Foundation.h>
@interface RegEdit : NSObject
@property(readonly) uint32 regSetting;
-(id) initWithValue:(uint32)value;
// 实现数组型自定义下标必须实现的两个方法
-(id) objectAtIndexedSubscript:(NSInteger)index;
-(void) setObject:(id)newValue atIndexedSubscript:(NSUInteger)index;
@end
#import "RegEdit.h"
#import "RegEditConstants.h"
@interface RegEdit()
@property(readwrite) uint32 regSetting;
@end
@implementation RegEdit
// 寄存器的初始化设置
-(id) initWithValue:(uint32)value{
if ((self = [super init])) {
_regSetting = value;
}
return self;
}
// 读寄存器操作,操作单位为1个字节(8位)
-(id) objectAtIndexedSubscript:(NSInteger)index{
NSUInteger byteNumber = index * 8;
if ((1 << byteNumber) > self.regSetting) {
[NSException raise:NSRangeException format:@"Byte selected(%ld) exceeds number value", index];
}
unsigned int byteValue = (self.regSetting & (kByteMultiplier << byteNumber)) >> byteNumber;
return [NSNumber numberWithUnsignedInt:byteValue];
}
// 写寄存器操作,操作单位为1个字节(8位)
-(void) setObject:(id)newValue atIndexedSubscript:(NSUInteger)index{
if (newValue == nil) {
[NSException raise:NSInvalidArgumentException format:@"New value is nil"];
}
NSUInteger byteNumber = index * 8;
if ((1 << byteNumber) > self.regSetting) {
[NSException raise:NSRangeException format:@"Byte selected(%ld) exceeds number value", index];
}
uint32 mask = ~(kByteMultiplier << byteNumber);
uint32 tmpValue = self.regSetting & mask;
unsigned char newByte = [newValue unsignedIntegerValue];
self.regSetting = (newByte << byteNumber) | tmpValue;
}
@end
命令行解析类
用于解析命令行并判断其有效性的CLIParser类。
#import <Foundation/Foundation.h>
@interface CLIParser : NSObject
-(id) initWithCount:(int)argc arguments:(const char *[])argv;
-(BOOL) parseWithRegister:(uint32 *)registerValue byteNumber:(NSInteger *)byteN doSetByte:(BOOL *)doSet byteValue:(unsigned int *)byteValue error:(NSError **)anError;
@end
#import "CLIParser.h"
#import "RegEditConstants.h"
NSString *HelpCommand = @"\n RegEdit -n [Hex initial register settings] -b [byte number] -v [hex byte value]";
NSString *HelpDesc = @"\n\nName\n RegEdit - Get/set selected byte of a register";
NSString *HelpSynopsis = @"\n\nSYNOPSIS";
NSString *HelpOptions = @"\n\nOPTIONS";
NSString *HelpRegValue = @"\n -n\tThe initial register settings.";
NSString *HelpRegByte = @"\n -b\tThe byte to retrieve from the register.";
NSString *HelpByteValue = @"\n -v\tValue to set for the selected register byte.";
@implementation CLIParser
{
const char **argValues;
int argCount;
}
// 接收传入参数
-(id) initWithCount:(int)argc arguments:(const char *[])argv{
if ((self = [super init])) {
argCount = argc;
argValues = argv;
}
return self;
}
// 判断命令行语句的合法性
-(BOOL) parseWithRegister:(uint32 *)registerValue byteNumber:(NSInteger *)byteN doSetByte:(BOOL *)doSet byteValue:(unsigned int *)byteValue error:(NSError *__autoreleasing *)anError{
// 使用NSUserDefaults类获取命令行参数
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *numberString = [defaults stringForKey:@"n"];
NSString *byteString = [defaults stringForKey:@"b"];
NSString *valueString = [defaults stringForKey:@"v"];
// 如果用户没用提供寄存器值或字节数,就显示帮助信息
if (!numberString || !byteString) {
NSString *help = [NSString stringWithFormat:@"%@%@%@%@%@%@%@",HelpDesc,HelpSynopsis,HelpCommand,HelpOptions,HelpRegValue,HelpRegByte,HelpByteValue];
printf("%s\n", [help UTF8String]);
return NO;
}
// 检查输入的寄存器值
NSScanner *scanner = [NSScanner scannerWithString:numberString];
// scanHexInt:方法返回值为是否从NSString对象中找到有效的十六进制整数
if (!numberString || ([numberString length] == 0) || ([numberString length] > kRegisterSize * 2) || ![scanner scanHexInt:registerValue]) {
if(anError != NULL){
NSString *msg = [NSString stringWithFormat:@"ERROR!, Register value must be from 1-%ld hexadecimal characters", kRegisterSize * 2];
NSString *description = NSLocalizedString(msg, @"");
NSDictionary *info = @{NSLocalizedDescriptionKey:description};
int errorCode = 1;
*anError = [NSError errorWithDomain:@"CustomErrorDomain" code:errorCode userInfo:info];
}
return NO;
}
// 检查输入的寄存器字节数
scanner = [NSScanner scannerWithString:byteString];
if (!byteString || ([byteString length] == 0) || [scanner scanInteger:byteN]) {
unsigned int numberLength = (unsigned int)(ceil([numberString length] * 0.5));
if ((*byteN < 0) || (*byteN > (numberLength - 1))) {
if (anError != NULL) {
NSString *msg = [NSString stringWithFormat:@"ERROR!, Register byte number must be from 0-%d", numberLength - 1];
NSString *description = NSLocalizedString(msg, @"");
NSDictionary *info = @{NSLocalizedDescriptionKey:description};
int errorCode = 2;
*anError = [NSError errorWithDomain:@"CustomErrorDomain" code:errorCode userInfo:info];
}
return NO;
}
}
// 检查用于设置寄存器字节内容的输入值
if (valueString) {
// 写操作标识符设为真
*doSet = YES;
scanner = [NSScanner scannerWithString:valueString];
if([scanner scanHexInt:byteValue]){
if (*byteValue > UCHAR_MAX) {
if (anError != NULL) {
NSString *msg = [NSString stringWithFormat:@"ERROR!, Register byte value must be 1-2 hexadecimal characters"];
NSString *description = NSLocalizedString(msg, @"");
NSDictionary *info = @{NSLocalizedDescriptionKey:description};
int errorCode = 3;
*anError = [NSError errorWithDomain:@"CustomErrorDomain" code:errorCode userInfo:info];
}
return NO;
}
}
}
return YES;
}
@end
测试
首先设置运行程序时传递的参数
点击下图中标记处,选择Edit Scheme:
在弹出窗口的下图标记位置输入命令行参数 “-n 1FB2C3A6 -b 0 -v A5”(可自定义)
最后在main.m中进行测试:
#import <Foundation/Foundation.h>
#import "RegEdit.h"
#import "CLIParser.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 使用CLIParser对象获取命令行参数
CLIParser *parser = [[CLIParser alloc] initWithCount:argc arguments:argv];
uint32 registerValue;
NSInteger registerByte;
unsigned int byteValue;
BOOL isSetByte;
NSError *error;
BOOL success = [parser parseWithRegister:®isterValue byteNumber:®isterByte doSetByte:&isSetByte byteValue:&byteValue error:&error];
if (!success) {
// 将错误记录到日志中并退出
if (error) {
NSLog(@"%@",[error localizedDescription]);
return -1;
}
}
else{
// 创建一个RegEdit对象并设置它的初始值
RegEdit *regEdit = [[RegEdit alloc] initWithValue:registerValue];
NSLog(@"Initial register settings -> 0x%X", (uint32)[regEdit regSetting]);
// 使用自定义下标获取选中的寄存器字节
NSNumber *byte = regEdit[registerByte];
NSLog(@"Byte %ld value retrieved -> 0x%X", (long)registerByte, [byte intValue]);
// 使用自定义下标将选中的寄存器字节的内容设置为输入值
if (isSetByte) {
NSLog(@"Setting byte %d value to -> 0x%X",(int)registerByte, byteValue);
regEdit[registerByte] = [NSNumber numberWithUnsignedInteger:byteValue];
NSLog(@"Updated register settings -> 0x%X", [regEdit regSetting]);
}
}
}
return 0;
}
运行结果:
2016-07-15 14:58:45.206 RegEdit[16984:163010] Initial register settings -> 0x1FB2C3A6
2016-07-15 14:58:45.207 RegEdit[16984:163010] Byte 0 value retrieved -> 0xA6
2016-07-15 14:58:45.207 RegEdit[16984:163010] Setting byte 0 value to -> 0xA5
2016-07-15 14:58:45.207 RegEdit[16984:163010] Updated register settings -> 0x1FB2C3A5
可以看到寄存器字节为0的值由十六进驻数A6修改成了十六进制数A5。