如何仅使用 C 中的 write() 函数输出字符的十六进制?
How can I output hex of characters using only write() function in C?
是否有可能将“%X”放入 write() 函数中以获得十六进制数的 ascii 字符?
如 printf("十六进制数 .. : %X").
提前致谢!
Are there any possibilities to put "%X" in write() function to get hex number of ascii characters?
没有。 %X
是 printf
系列 格式化 输出函数的一个特定特征。 ('f' 是“已格式化”的助记符。)write()
执行原始输出——正是您指定的字节。如果你想使用 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);
}
简答
由于 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
我们将(使用相同的逻辑)减去 10
来自 digitValue,然后向其添加 'A'
。由于字母字符在 ASCII 码中也是连续的,我们可以自由地使用 digitValue-10
作为 'A'
字符的偏移量。
char charDigit;
if (digitValue < 10) {
charDigit = '0' + digitValue;
}
else {
charDigit = 'A' + (digitValue-10);
}
所以如果 digitValue
是 0xA (10),那么 digitValue-10
就是 0
,并且将 0
添加到 'A'
只会让我们得到 'A'
.
将整数转换为十六进制字符串表示形式
除以 16 取模,我们得到最低有效(最右边)的十六进制数字。但是打印字符串是从左到右完成的,而不是从右到左。
因此,为了打印字符串表示形式,我们需要某种缓冲区来存储所有最右边的字符。请记住这一点——没有 int
值会有超过 8 个十六进制数字,因此我们可以自由分配一个 8 个字符的数组。
char digits[8];
int digitIndex = 8;
中的digitIndex
会一直记录我们写入的是哪个array slot,注意这里设置的是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);
假设 valueToConvert
不是负数,这应该会产生对应于给定 int
的十六进制值。
现在让我解释一下为什么我要先减去索引:我们将使用 digits+digitIndex
的值(这是一个 char *
)作为我们数字数组的起点。如果我先减去,然后把数字放在那个地方,那保证当循环退出时,digitIndex
结束第一个数字,这很方便。
现在让我们得到数组的长度:
unsigned count = 8 - digitIndex;
这就是我们缓冲区的大小减去数组中数字第一位的索引。
终于
将值转换为我们的数字数组后,我们只需调用 write
:
write(handle, digits+digitIndex, count);
全图:
void write_hex_of_int(int handle, int number)
{
char digits[8];
int digitIndex = 8;
// Fill the `digits` array with the digits of the number
int valueToConvert = number;
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);
// Get the actual width of the number and print it.
unsigned count = 8 - digitIndex;
write(handle, digits+digitIndex, count);
}
是否有可能将“%X”放入 write() 函数中以获得十六进制数的 ascii 字符?
如 printf("十六进制数 .. : %X").
提前致谢!
Are there any possibilities to put "%X" in write() function to get hex number of ascii characters?
没有。 %X
是 printf
系列 格式化 输出函数的一个特定特征。 ('f' 是“已格式化”的助记符。)write()
执行原始输出——正是您指定的字节。如果你想使用 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);
}
简答
由于 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
我们将(使用相同的逻辑)减去 10
来自 digitValue,然后向其添加 'A'
。由于字母字符在 ASCII 码中也是连续的,我们可以自由地使用 digitValue-10
作为 'A'
字符的偏移量。
char charDigit;
if (digitValue < 10) {
charDigit = '0' + digitValue;
}
else {
charDigit = 'A' + (digitValue-10);
}
所以如果 digitValue
是 0xA (10),那么 digitValue-10
就是 0
,并且将 0
添加到 'A'
只会让我们得到 'A'
.
将整数转换为十六进制字符串表示形式
除以 16 取模,我们得到最低有效(最右边)的十六进制数字。但是打印字符串是从左到右完成的,而不是从右到左。
因此,为了打印字符串表示形式,我们需要某种缓冲区来存储所有最右边的字符。请记住这一点——没有 int
值会有超过 8 个十六进制数字,因此我们可以自由分配一个 8 个字符的数组。
char digits[8];
int digitIndex = 8;
中的digitIndex
会一直记录我们写入的是哪个array slot,注意这里设置的是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);
假设 valueToConvert
不是负数,这应该会产生对应于给定 int
的十六进制值。
现在让我解释一下为什么我要先减去索引:我们将使用 digits+digitIndex
的值(这是一个 char *
)作为我们数字数组的起点。如果我先减去,然后把数字放在那个地方,那保证当循环退出时,digitIndex
结束第一个数字,这很方便。
现在让我们得到数组的长度:
unsigned count = 8 - digitIndex;
这就是我们缓冲区的大小减去数组中数字第一位的索引。
终于
将值转换为我们的数字数组后,我们只需调用 write
:
write(handle, digits+digitIndex, count);
全图:
void write_hex_of_int(int handle, int number)
{
char digits[8];
int digitIndex = 8;
// Fill the `digits` array with the digits of the number
int valueToConvert = number;
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);
// Get the actual width of the number and print it.
unsigned count = 8 - digitIndex;
write(handle, digits+digitIndex, count);
}