题
嘿大家,只是一个快速的事情,我有十六进制到整数工作,但我需要将数字小写。这就是我所拥有的,任何想法让A至F F不敏感吗?
int htoi(char f[]) {
int z, n;
n = 0;
for (z = 0; f[z] >= '0' && f[z] <= 'F'; ++z)
if (f[z] >= 'A' && f[z] <= 'F')
n = 10 + 16 * n + (f[z] - 'A');
else
n = 16 * n + (f[z] - '0');
}
可能只是一件小事,但我想加入a-f和A-F。谢谢你的帮助!
解决方案
如果你这样做是为了学习如何做,请忽略这篇文章。如果您正在使用此函数,因为您需要将十六进制数字的字符串转换为 int
,那么您应该在标准库中进行操作。标准函数 strtol()
转换字符串到 long
,可以转换为 int
(或者 unsigned int
)。第三个参数是转换为的基数 - 在这种情况下,您希望16进制十六进制。此外,如果给定基数为0,如果字符串以 0x
开头,则为半角形,如果以 0
开头,则为octal,否则为十进制。这是一个非常有用的功能。
编辑:注意到这一点,但是当我们在这里时,值得一提的是你通常不应该使用
int
来索引数组。 C标准定义了一种名为 size_t
的类型,用于存储数组索引。它通常是 unsigned int
或 unsigned long
或其他东西,但保证足够大以存储您可以使用的任何数组或指针偏移量。
使用 int
的问题在于,理论上,有一天,某人可能会传递一个比 INT_MAX
更长的字符串,然后你的 int
将溢出,可能会回绕,并开始读取内存,它可能不应该因为它使用负索引。这是非常不可能的,特别是对于这样的函数,因为返回的 int
值会在 int
计数器溢出之前很久就会溢出,但它是要记住一件重要的事情。
为了在技术上正确,你应该只使用 size_t
类型变量来索引数组,或者至少只使用 unsigned
类型,除非你真的想尝试访问否定元素(除非你知道你在做什么,这通常是一个坏主意)。但是,这不是一个大问题。
其他提示
创建另一个函数,将十六进制数字转换为整数:
int hex_digit_to_integer(char digit) {
if (digit >= 'A' && digit <= 'F') {
return digit - 'A' + 10;
} else if (digit >= 'a' && digit <= 'f') {
return digit - 'a' + 10;
} else if (digit >= '0' && digit <= '9') {
return digit - '0';
}
return -1; // Bad input.
}
注意它如何处理四种情况:
* digit
是一个大写字母 A..F
,
* digit
是一个小写字母 a..f
,
* digit
是十进制数字 0..9
,和
* digit
不是上述内容。
现在在原始函数中使用新函数:
int htoi(char f[]) {
int z, n;
n = 0;
/* Loop until we get something which isn't a digit (hex_digit_to_integer returns something < 0). */
for (z=0; hex_digit_to_integer(f[z]) >= 0; ++z) {
n = 16 * n + hex_digit_to_integer(f[z]);
}
}
请注意新功能的清晰度是多少?
如果你喜欢冒险,你可以使用这个神奇的功能(它不能处理错误的输入,所以你需要事先检查一下):
int hex_digit_to_integer(char digit) {
return digit - (digit & 64 ? 55 : 48) & 15;
}
用专用变量替换所有f [z]。使用toupper(f [z])
分配该变量以下是NPS NSRL Bloom包中的一些代码:
static int *hexcharvals = 0;
/** Initialization function is used solely for hex output
*/
static void nsrl_bloom_init()
{
if(hexcharvals==0){
/* Need to initialize this */
int i;
hexcharvals = calloc(sizeof(int),256);
for(i=0;i<10;i++){
hexcharvals['0'+i] = i;
}
for(i=10;i<16;i++){
hexcharvals['A'+i-10] = i;
hexcharvals['a'+i-10] = i;
}
}
}
/**
* Convert a hex representation to binary, and return
* the number of bits converted.
* @param binbuf output buffer
* @param binbuf_size size of output buffer in bytes.
* @param hex input buffer (in hex)
*/
int nsrl_hex2bin(unsigned char *binbuf,size_t binbuf_size,const char *hex)
{
int bits = 0;
if(hexcharvals==0) nsrl_bloom_init();
while(hex[0] && hex[1] && binbuf_size>0){
*binbuf++ = ((hexcharvals[(unsigned char)hex[0]]<<4) |
hexcharvals[(unsigned char)hex[1]]);
hex += 2;
bits += 8;
binbuf_size -= 1;
}
return bits;
}
此代码设计为超快,处理大写和小写十六进制,并处理任意长度的十六进制字符串。函数nsrl_hex2bin()接受二进制缓冲区,该缓冲区的大小以及要转换的十六进制字符串。它返回实际转换的位数。
哦,如果你只想要一个整数,那么你可以乘以字节(对于与字节无关的代码),或者只是进行强制转换(对于依赖于字节的代码)。
您可以尝试 sscanf :
#include <stdio.h>
...
//NOTE: buffer overflow if f is not terminated with \0 !!
int htoi(char f[]){
int intval = -1;
if (EOF == sscanf(f, "%x", &intval))
return -1; //error
return intval;
}
两个选项:
在进行扫描之前转换为大写。
在处理小写的四个循环中添加第二个if。
请改为尝试:
int htoi (char f[]) {
int z, n;
n = 0;
for (z = 0; f[z] != '\0'; ++z) {
if (f[z] >= '0' && f[z] <= '9') {
n = n * 16 + f[z] - '0';
} else {
if (f[z] >= 'A' && f[z] <= 'F') {
n = n * 16 + f[z] - 'A' + 10;
} else {
if (f[z] >= 'a' && f[z] <= 'f') {
n = n * 16 + f[z] - 'a' + 10;
} else {
break;
}
}
}
}
return n;
}
它仍然以与你相同的方式处理输入(我倾向于使用指针,但它们有时很难被初学者理解)但引入了三个独立的情况,0-9,AF和af,适当地处理每个。
您的原始代码实际上会允许错误的字符('9'和'A'之间的六个字符)并根据它们产生不正确的结果。
请注意,此新代码通常仅在字符串结尾处终止循环。找到无效的十六进制字符将突破循环,在功能上与终止条件相同。
请使用strtol()。这是标准的C90功能,比大多数天真的实现功能强大得多。它还支持从dec(无前缀),十六进制(0x)和oct(从0开始)的无缝转换。
使用shift旋转而不是乘法实现。
int HexToDec(char *Number)
{
unsigned int val = 0;
int i , nibble;
for(i = strlen( Number ) - 1; i >= 0; --i, nibble += 4)
{
const char hex = Number[i];
if (hex >= '0' && hex <= '9')
val += (hex - '0')<<nibble;
else if (hex >= 'A' && hex <= 'F')
val += (hex - 'A' + 10)<<nibble;
else if (hex >= 'a' && hex <= 'f')
val += (hex - 'a' + 10)<<nibble;
else
return -1;
}
return val;
}