【问题标题】:How to fprintf properly on my character struct array that contains Hex byte characters如何在包含十六进制字节字符的字符结构数组上正确地 fprintf
【发布时间】:2014-04-09 15:21:46
【问题描述】:

这是我的问题,我有一个如下所示的字节结构:

struct machinecode{
    char byte1[2];
    char byte2[2];
    char byte3[2];
    char byte4[2];
    char byte5[2];
    char byte6[2];
    char byte7[2];
    char byte8[2];
    char byte9[2];
};
struct machinecode WRITEME[500];

现在,这些 2 字节字符或字符串的集合被格式化为十六进制字节,例如:

byte1 = "01"

byte2 = "C0"

char 字节的分配方式如下:

...
char * returner
...
strncpy(WRITEME[index].byte1, "00", 2);
strncpy(WRITEME[index].byte2, returner, 2);

我的打印代码如下所示:

while(counter < max){
...
    else if(prog_counter[counter2] == 2){
            fprintf(w, ???, WRITEME[counter].byte1);
            fprintf(w, ???, WRITEME[counter].byte2);
    }
...
}

现在我希望将字符串打印为十六进制字节,我需要为 fprintf 使用哪种格式(???)?还是我需要先将此十六进制字节字符串转换为 int,然后再打印它们?

我尝试了“%x”、“%X”,但它们不起作用。

编辑:

我想补充一点,我正在制作一个 .com 可执行文件,所以我需要将它们打印为十六进制字节。

【问题讨论】:

  • 你是如何给 bytes[] 数组赋值的? “01”是字符串?
  • 它们被分配了字符串。所以在 ascii 中:“48 49”
  • 你能把实际分配给WRITEME[counter].byte1吗?错误的方式很多,正确的方式更少。
  • 这里是一个例子:char * returner; strncpy(WRITEME[index].byte1, "00", 2); strncpy(WRITEME[index].byte2, returner, 2);
  • 考虑一个数组:char byte[9][2];,而不是 9 个结构成员。记住数组索引从 0 开始。

标签: c formatting printf


【解决方案1】:

修改后的答案

你说“我正在制作一个.COM 可执行文件,所以我需要将它们打印为十六进制字节”。立即的反应是“你到底为什么要首先将这些值转换成一对字节?”您必须将它们转换回单个字节,然后使用%c 表示法写入该字节。一种可能不是最好的方法是:

static const char hexits[] = "0123456789ABCDEF";
static inline int byte_from_hex(const char *hex)
{
    assert(isxdigit(hex[0]) && isxdigit(hex[1]));
    int b1 = strchr(hexits, toupper((unsigned char)hex[0])) - hexits;
    int b2 = strchr(hexits, toupper((unsigned char)hex[1])) - hexits;
    return b1 * 16 + b2;
}

fprintf(w, "%c", byte_from_hex(WRITEME[counter].byte1);

但一开始不转换为字符串会简单得多。

原答案

由于您的数据不是以空值结尾的,因此您需要在转换规范中使用长度,如fprintf() 手册页中所述:

%.2s

这意味着从字符数组中最多打印 2 个字符。

fprintf(w, "%.2s", WRITEME[counter].byte1);

这假设你做了类似的事情:

WRITEME[counter].byte1[0] = '0';
WRITEME[counter].byte2[1] = '1';

或:

memmove(WRITEME[counter].byte1, "01", sizeof(WRITEME[counter].byte1);

或者(正如 cmets 显示的那样):

strncpy(WRITEME[counter].byte1, "01", 2);  // or sizeof(WRITEME[counter].byte1)

而你没有做了类似的事情:

sprintf(WRITEME[counter].byte1, "%2X", byte_value);

而你没有做了类似的事情:

strcpy(WRITEME[counter].byte1, "01");

【讨论】:

  • 我想我需要创建一个将十六进制转换为整数的函数,因为 c 语言没有直接的打印格式,可以将十六进制转换为整数或字符
  • 您几乎可以使用sscanf(),因为它是为将字符串转换为其他类型而设计的,但它需要以空字符结尾的字符串作为输入,并且您没有以空字符结尾的字符串。您可以尝试int byte_val; sscanf(WRITEME[counter].byte1, "%2x", &amp;byte_val); fprintf(w, "%c", byte_val);,我认为它应该是安全的,因为您已将其限制为最多读取 2 个字符,并且无需担心前导空格。但它正在如履薄冰。您确定不能使用0x01 代替"01"
  • 我可以使用 0x 格式,但可能会编辑很多 strncpy 并更改结构格式。但在此之前,我会尝试您建议的 sscanf 函数。回答你的问题:“你到底为什么要把这些值转换成一对字节?”我选择显示十六进制字节字符串格式,这样我就可以轻松调试和比较我的汇编器是否喷出正确的操作码。我实际上是在使用二进制格式,但只是在打印过程中将其转换为十六进制字节,因为我短视地假设 C print 可以直接将十六进制转换为字节
  • 我刚刚尝试了 sscanf 和 fprintf 方法,看起来它可以工作,但是导出的 .com 文件中的随机“0d”字节。我无法追踪它的错误,你知道是什么导致 fprint 写入“0d”字节或回车吗?我已经看够了,我找不到是什么原因造成的
  • 您是否打开文件以写入二进制文件?如果您将其作为文本文件打开,您会发现每次写入 0x0A(^J,newlinw)字节时,系统都会事先写入 0x0D(^M,回车)字节。否则,没有明显的原因需要额外的字节......我从你的“答案”中看到这确实是问题所在!
【解决方案2】:

这是我解决此问题的方法。

首先我使用Jonathan's solution 使用 sscanf 和 printf。

然后我遇到了一个奇怪的错误,它将随机“0d”放在我的文件中。

解决方案是以二进制模式打开和写入文件。

w = fopen( filename , "wb" );

希望这对未来的其他用户有所帮助

【讨论】:

    猜你喜欢
    • 2012-06-05
    • 2014-10-07
    • 2013-08-18
    • 2013-01-14
    • 2013-08-09
    • 2013-10-13
    • 1970-01-01
    • 2019-12-26
    相关资源
    最近更新 更多