【问题标题】:Getting a hexadecimal number into a program via the command line通过命令行将十六进制数输入程序
【发布时间】:2010-01-29 15:15:57
【问题描述】:

我可以这样做:

int main(int argc, char** argv) {
  unsigned char cTest = 0xff;
  return 0;
}

但是通过命令行将十六进制数字输入程序的正确方法是什么?

unsigned char cTest = argv[1];

不成功。这会产生 initialization make integer from pointer without a cast 警告。

【问题讨论】:

  • 命令行参数是 always 字符串。某些平台可能会将它们设为 Unicode,在这种情况下,简单的 strtol 将不起作用。
  • @dirkgently:在这种情况下,mbstol 或任何多字节或宽字符(或 TCHAR)变体将涵盖这一点? (鉴于问题的性质,我也怀疑这是一个关键问题
  • @dirkgently: 在这种情况下,main() 的第二个参数不是char ** 类型吗?这不能符合标准。
  • @Alok:它们仍然可以是多字节的,在这种情况下 mbstoul 是最好的,但在我认为的问题的上下文中这太花哨了

标签: c base-conversion strtol


【解决方案1】:

我想有些人到达这里可能只是在寻找:

$ ./prog `python -c 'print "\x41\x42\x43"'`
$ ./prog `perl -e 'print "\x41\x42\x43"'`
$ ./prog `ruby -e 'print "\x41\x42\x43"'`

【讨论】:

  • 我是。非常感谢!
  • 感谢负载 - 非常非常有帮助
【解决方案2】:

正如main 的类型所表明的那样,命令行中的参数是字符串,需要转换为不同的表示形式。

将单个十六进制命令行参数转换为十进制看起来像

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  printf("%ld\n", strtol(argv[1], NULL, 16));

  return 0;
}

示例用法:

$ ./hex ff
255

使用 strtol 并将最终参数从 16 更改为 0,如

printf("%ld\n", strtol(argv[1], NULL, 0));

使程序接受十进制、十六进制(前导 0x 和八进制(前导 0 表示)值:

$ ./num 0x70
112
$ ./num 070
56
$ ./num 70
70

使用 bash 命令 shell,利用 ANSI-C Quoting 让 shell 执行转换,然后您的程序只需从命令行打印值。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  int i;
  for (i = 1; i < argc; i++) {
    unsigned char value = argv[i][0];
    if (strlen(argv[i]) > 1)
      fprintf(stderr, "%s: '%s' is longer than one byte\n", argv[0], argv[i]);

    printf(i + 1 < argc ? "%u " : "%u\n", value);
  }

  return 0;
}

Bash 支持$'...' 形式的多种格式,但$'\xHH' 似乎与您的问题最匹配。例如:

$ ./print-byte $'\xFF' $'\x20' $'\x32'
255 32 50

也许你将命令行中的值打包成一个字符串并打印出来。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
  int i;

  if (argc > 1) {
    char *s = malloc(argc);
    if (!s) {
      fprintf(stderr, "%s: malloc: %s\n", argv[0], strerror(errno));
      return 1;
    }

    for (i = 1; i < argc; i++)
      s[i - 1] = strtol(argv[i], NULL, 16) & 0xff;

    s[argc - 1] = '\0';
    printf("%s\n", s);
    free(s);
  }

  return 0;
}

在行动:

$ ./pack-string 48 65 6c 6c 6f 21
Hello!

以上所有内容都在重新发明 bash 和操作系统已经为您提供的轮子。

$ echo $'\x48\x65\x6c\x6c\x6f\x21'
Hello!

echo 程序将其命令行参数打印在标准输出上,您可以将其视为对参数的 for 循环和每个参数的 printf

如果您有另一个程序为您执行解码,请使用Command Substitution 将反引号或$() 包围的命令替换为其输出。请参阅下面的示例,这些示例再次使用 echo 作为占位符。

$ echo $(perl -e 'print "\x50\x65\x72\x6c"')
Perl
$ echo `python -c 'print "\x50\x79\x74\x68\x6f\x6e"'`
Python

【讨论】:

    【解决方案3】:

    您可以使用 strtoul 遍历字符串中的字符并转换它们,同时考虑到您传入的基数(在此上下文中为 16):-

    char *terminatedAt;
    if (argc != 2)
        return 1;
    
    unsigned long value = strtoul( argv[1], &terminatedAt, 16);
    
    if (*terminatedAt != '\0')
        return 2;
    
    if (value > UCHAR_MAX)
        return 3;
    
    unsigned char byte = (unsigned char)value;
    printf( "value entered was: %d", byte);
    

    正如其他示例中所述,有更短的方法,但它们都不允许您彻底错误检查处理过程(如果有人通过 FFF 而您只有 unsiged char 将其放入?

    例如sscanf:

    int val;
    sscanf(argv[1], &val)
    printf("%d\n", val); 
    

    【讨论】:

    • UCHAR_MAX 可能大于LONG_MAX,所以你应该使用strtoul(),而value &gt; 255 应该是value &gt; UCHAR_MAX。最后,static_cast 是 C++;由于隐式转换规则,在这里您不需要强制转换。
    • Ta,我在初始版本中有一个cout:P 我最初考虑使用 u 但认为这会使问题变得过于复杂,因为提问者主要是想理解一个不能立即理解的概念对他们来说很明显。
    • 我同意有时必须为初学者做出并非完全学究式正确的事情,但在这种情况下,我认为学究式并不太难,即使对于初学者也是如此。它将阻止许多人假设UCHAR_MAX == 255LONG_MAX &gt; UCHAR_MAX 等。感谢您的编辑和一个好的答案!
    • @Alok:总是乐于迂腐,谢谢!我认为这里的演员阵容很好,因为它解释了发生在读者身上的事情,并且会避免关于缩短转换应该打开的警告。我将忽略 mbs 问题(以及 wchar_t 问题,因为问题排除了它们)。一遍又一遍!
    【解决方案4】:
    unsigned char cTest = argv[1];
    

    错了,因为argv[1] 的类型是char *。如果argv[1] 包含"0xff" 之类的内容,并且您想将与之对应的整数值分配给unsigned char,最简单的方法可能是使用strtoul() 首先将其转换为unsigned long,然后检查转换后的值是否小于或等于UCHAR_MAX。如果是,您可以分配给cTest

    strtoul()的第三个参数是一个基数,可以为0表示C风格的数字解析(允许八进制和十六进制字面量)。如果您只想允许基数为 16,请将其作为第三个参数传递给 strtoul()。如果您想允许任何基数(这样您就可以解析0xff0377255 等),请使用 0。

    UCHAR_MAX&lt;limits.h&gt; 中定义。

    【讨论】:

    • +1 很好的解释,考虑到我试图在代码中显示的大部分观点背后的推理
    【解决方案5】:

    在 C 中做这种事情的传统方法是使用scanf()。它与 printf() 完全相反,读取文件(或终端)的给定格式 out 并写入您列出的变量中,而不是将它们写入其中。

    在您的情况下,您将使用sscanf,因为您已经将它放在字符串而不是流中。

    【讨论】:

      【解决方案6】:

      atoiatolstrtoistrtol

      全部在stdlib.h

      【讨论】:

      • 所有人都在 3 分钟前指出(另请参阅链接的手册页),但没有帮助提问者理解为什么它是必要的或提供样本。当帖子未添加时,最好将其删除以保持干燥
      猜你喜欢
      • 1970-01-01
      • 2017-11-13
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 1970-01-01
      • 2019-02-05
      • 2017-08-22
      • 1970-01-01
      相关资源
      最近更新 更多