13

我可以做这个:

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

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

unsigned char cTest = argv[1];

不成功。这会产生一个初始化,从指针生成整数而没有强制转换警告。

4

6 回答 6

17

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

$ ./prog `python -c 'print "\x41\x42\x43"'`
$ ./prog `perl -e 'print "\x41\x42\x43"'`
$ ./prog `ruby -e 'print "\x41\x42\x43"'`
于 2011-07-16T16:33:54.353 回答
11

如类型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 引用让 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每个循环。

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

$ echo $(perl -e 'print "\x50\x65\x72\x6c"')
Perl
$ echo `python -c 'print "\x50\x79\x74\x68\x6f\x6e"'`
Python
于 2010-01-29T15:20:54.453 回答
7

您可以使用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); 
于 2010-01-29T15:19:09.883 回答
4
unsigned char cTest = argv[1];

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

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

UCHAR_MAX中定义<limits.h>

于 2010-01-29T15:23:12.620 回答
1

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

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

于 2010-01-29T15:24:49.450 回答
-3

atoi, atol, strtoi,strtol

全部在stdlib.h

于 2010-01-29T15:21:50.110 回答