问题描述
是否有可能在 write() 函数中放入 "%X" 以获得十六进制数的 ascii 字符?
就像 printf("Hex number of .. : %X").
先谢谢你!
解决方法
是否有可能在 write() 函数中放入 "%X" 以获得十六进制数的 ascii 字符?
没有。 %X
是 格式化 输出函数的 printf
系列的特定特征。 ('f' 是“格式化”的助记符。)write()
执行原始输出——正是您指定的字节。如果您想使用 write()
,那么您必须自己执行格式化,我认为这是作业重点的很大一部分。
简答
由于 write
不接受格式字符串和其他参数,因此您必须使用 printf
,或者实现您自己的函数,该函数接受一个整数并将其转换为十六进制表示。
下面我将描述如何编写您自己的类似 %X
的输出以及它是如何工作的。
将字符转换为十六进制字符
通过将数字除以 16 并重复取模,您可以将整数(以及字符的十六进制代码)转换为十六进制字符串。
例如,让我们考虑 'A'
的值,它是 41
的十六进制。该数字除以 16 的余数等于其最后一位数字的值 -- 1
。然后,如果我们将值 0x41
除以 16,我们会得到相同的数字,但没有最后一位——0x4
。
可以想到这样迭代的一个步骤:
int valueToConvert = 'A';
int lastHexDigit = valueToConvert % 16; // get the value of the last hex digit
valueToConvert = valueToConvert / 16; // save the remainder of the number
这让我们得到最后一个十六进制数字的值(作为整数)。
现在我们要将这个数字的整数值转换为char
,即将值0
转换为'0'
。由于 ASCII 中的字符是连续存储的,我们可以通过将 '0'
添加到我们要转换的整数值来获得数字的值。
char charDigit = '0' + digitValue;
上面的代码片段仅适用于小于或等于 digitValue
的 9
。对于数字 A
到 F
,我们需要添加一个条件,如果 digitValue
大于 9
,我们将(使用相同的逻辑)减去 {{1} } 从 digitValue ,然后添加 10
到它。由于字母字符在 ASCII 代码中也是连续的,我们可以自由地使用 'A'
作为 digitValue-10
字符的偏移量。
'A'
所以如果 char charDigit;
if (digitValue < 10) {
charDigit = '0' + digitValue;
}
else {
charDigit = 'A' + (digitValue-10);
}
是 0xA (10),那么 digitValue
是 digitValue-10
,将 0
添加到 0
只会让我们得到 {{1} }.
将整数转换为十六进制字符串表示
通过对除以 16 取模,我们得到最不重要(最右边)的十六进制数字。但是打印字符串是从左到右,而不是从右到左。
因此,为了打印字符串表示,我们需要某种缓冲区来存储我们最右边的所有字符。请记住这一点——任何 'A'
值都不会超过 8 个十六进制数字,因此我们可以自由分配 8 个字符的数组。
'A'
int
将跟踪我们写入的数组槽。请注意,它设置为 char digits[8];
int digitIndex = 8;
,而不是 digitIndex
,这是我稍后解释的原因。
现在让我们放回之前的代码——我们将使用 8
来“将最后一位数字放入数组的最后一个位置,直到余数为零”。
7
假设 do/while
不是负数,这应该产生对应于给定 int valueToConvert = ...; // leaving the declaration here for clarity
do {
// Get the value of the last digit
int lastDigit = valueToConvert % 16;
// Convert the last digit to char
char charDigit;
if (lastDigit < 10) {
charDigit = '0' + lastDigit;
}
else {
charDigit = 'A' + (lastDigit-10);
}
// Put the last digit into the array
digitIndex -= 1;
digits[digitIndex] = charDigit;
valueToConvert /= 16;
} while(valueToConvert != 0);
的十六进制值。
现在让我解释为什么我要先减去索引:我们将使用 int
的值(它是一个 valueToConvert
)作为我们的数字数组的起点。如果我先减去然后把数字放在那个位置,那保证当循环退出时,digits+digitIndex
超过第一个数字,非常方便。
现在让我们得到数组的长度:
char *
这只是缓冲区的大小减去数组中数字第一位的索引。
终于
将值转换为我们的数字数组后,我们只需调用 digitIndex
:
unsigned count = 8 - digitIndex;
全图:
write
,
您需要编写自己的函数。
char toHexDigit(int x)
{
char result;
if(x > 15) x = 0;
if((x >= 0 && x < 10)) result = '0' + x;
else result = 'A' + x - 10;
return result;
}
char *tohex(unsigned x)
{
static char buff[sizeof(x)*2];
for(ssize_t i = 0; i < sizeof(x) * 2; i++)
{
int shift = (sizeof(x) * 2 - i - 1) * 4;
buff[i] = toHexDigit((x & (0xf << shift)) >> shift);
}
return buff;
}
int main(void)
{
write(1,tohex(0xD2A45678),sizeof(unsigned)*2);
}