您的位置:首页 > 理论基础

[精通Objective-C] 使用自定义下标模拟32位计算机寄存器操作

2016-07-15 16:02 337 查看

[精通Objective-C] 使用自定义下标模拟32位计算机寄存器操作

参考书籍:《精通Objective-C》【美】 Keith Lee

目录

精通Objective-C 使用自定义下标模拟32位计算机寄存器操作
目录

程序功能简介

寄存器类

命令行解析类

测试

程序功能简介

创建一个命令行程序用于模拟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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息