我正在尝试将
uint16_t
值转换为该数字的十六进制表示形式,作为 C 中的字符串,而不使用任何外部库。到目前为止,我已经通过 this 答案实现了可靠的转换。
但是,如果 uint16_t
值小于 0x1000
,我的用例要求结果输出用前导零填充。例如,如果我像这样调用该函数:
char s[5];
itohexa(s, 1230); //(1230->0x04CE)
我会得到:
04CE
但是,这个函数给了我这个:
4CE
字符串中表示的 uint16_t 的实际字节数对于我的用例很重要。我预计该值偶尔会超过
0x0FFF
,因此仅向任何 uint16_t
数字添加前导零字符(到目前为止我一直在这样做作为解决方法),是不够的。
这是我尝试过的:
static char *itohexa_helper(char *dest, uint16_t x, uint8_t pad) {
if (x >= 16 || pad) {
dest = itohexa_helper(dest, x/16, pad);
pad = 1;
}
*dest++ = "0123456789ABCDEF"[x & 15];
return dest;
}
char *itohexa(char *dest, uint16_t x) {
uint8_t padding = (x < 0x1000);
*itohexa_helper(dest, x, padding) = '\0';
return dest;
}
在这种情况下,即使该值的前 4 个最高有效位为零,
padding
和 pad
是否仍会进行转换?
仅供记录:对上述代码所做的修改仍然会产生与上面链接的answer中提到的原始结果相同的结果。
我可能会尽可能明确地写出来,就像这样(评论中的解释):
#define ZERO_PAD false
char* itohexa (char dest[4+1], uint16_t x)
{
bool remove_zeroes = true;
char* ptr = dest;
for(size_t i=0; i<4; i++)
{
// mask out the nibble by shifting 4 times byte number:
uint8_t nibble = (x >> (3-i)*4) & 0xF;
// binary to ASCII hex conversion:
char hex_digit = "0123456789ABCDEF" [nibble];
if(!ZERO_PAD && remove_zeroes && hex_digit == '0')
{
; // do nothing
}
else
{
remove_zeroes = false;
*ptr = hex_digit;
ptr++;
}
}
if(remove_zeroes) // was it all zeroes?
{
*ptr = '0';
ptr++;
}
*ptr = '\0';
return dest;
}
测试用例:
char dest[4+1];
puts(itohexa(dest, 0));
puts(itohexa(dest, 1230));
puts(itohexa(dest, 0));
puts(itohexa(dest, 0xC1));
puts(itohexa(dest, 0xABBA));
输出
ZERO_PAD false
:
0
4CE
0
C1
ABBA
输出
ZERO_PAD true
:
0000
04CE
0000
00C1
ABBA
ZERO_PAD
自然可以改为参数,或者你可以制作两个不同的函数等等
有时,使用(更复杂的)递归来解决问题比使用迭代更“有趣”。你的代码已经很接近了! 与其说你想要的“填充”,不如说它是前导的“0”。设置、清除填充标志可能会起作用(如果正确完成),但只会给您一个前导零。
这是您重新编写的代码:
static char *itohexa_helper( char *dest, uint16_t x, int n ) {
if( --n )
dest = itohexa_helper( dest, x>>4, n ); // recursion
*dest++ = "0123456789ABCDEF"[x & 0xF]; // mask and offset
return dest;
}
char *itohexa(char *dest, uint16_t x) {
*itohexa_helper( dest, x, 4 ) = '\0'; // 4 digits of output...
return dest;
}
int main( void ) {
char buf[16]; // big enough
puts( itohexa( buf, 0xBEEF ) );
puts( itohexa( buf, 0xCDE ) );
puts( itohexa( buf, 0xCD ) );
return 0;
}
输出:
BEEF
0CDE
00CD
注意没有任何以 10 为基数的常量...