Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 传递特殊字符作为参数_C_Bash - Fatal编程技术网

C 传递特殊字符作为参数

C 传递特殊字符作为参数,c,bash,C,Bash,我需要将一个十六进制为002C0021的字符串作为命令行参数传递给我的程序,这是我无法做到的 #include<stdio.h> int main(int argc,char* argv[]){ // argv[1] should have the string that the above hex represents //... the program will use that string inside the program //...also please exp

我需要将一个十六进制为
002C0021
的字符串作为命令行参数传递给我的程序,这是我无法做到的

#include<stdio.h>
int main(int argc,char* argv[]){

// argv[1] should have the string that the above hex represents 

//... the program will use that string inside the program

//...also please explain what should i do if i (am/am not) allowed to modify the source  

}

您应该让您的程序接受包含转义符的字符串,并自己解析它们。因此,可以这样调用它:

$ ./myprogram '\x00\x2c\x00\x21'
例如(
\x
与C本身使用的内容相匹配,因此用户可能很熟悉)。单引号是为了保护反斜杠不受shell的影响,不是100%确定,也不是在正确的提示下

结果不会是字符串,因为C中的字符串不能包含0个字符

下面是一个示例,展示了这一点:

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

static size_t decode(void *buf, size_t buf_max, const char *s)
{
    unsigned char *put = buf;
    unsigned char * const put_max = put + buf_max;
    while (*s != '\0' && put != put_max)
    {
        if (*s == '\\')
        {
            ++s;
            if (*s == '\\')
                *put++ = *s++;
            else if (*s == 'x')
            {
                ++s;
                char *endp;
                const unsigned long v = strtoul(s, &endp, 16);
                if (endp == s)
                    break;
                *put++ = (unsigned char) v;
                s = endp;
            }
            else
                break;
        }
        else
            *put++ = *s++;
    }
    return put - (unsigned char *) buf;
}

int main(int argc, char *argv[])
{
    unsigned char buf[32];
    const size_t len = decode(buf, sizeof buf, "\\x0hello\\x1\\xaa\\xfe\\xed");
    for (size_t i = 0; i < len; ++i)
    {
        printf("%x\n", buf[i]);
    }
    return 0;
}
#包括
#包括
#包括
静态大小解码(void*buf,size\t buf\u max,const char*s)
{
无符号字符*put=buf;
无符号字符*const put_max=put+buf_max;
而(*s!='\0'&&put!=put\u max)
{
如果(*s=='\\')
{
++s;
如果(*s=='\\')
*put++=*s++;
如果(*s=='x',则为else
{
++s;
char*endp;
常量无符号长v=strtoul(s和endp,16);
如果(endp==s)
打破
*put++=(无符号字符)v;
s=endp;
}
其他的
打破
}
其他的
*put++=*s++;
}
返回put-(unsigned char*)buf;
}
int main(int argc,char*argv[])
{
无符号字符buf[32];
const size_t len=decode(buf,sizeof buf,“\\x0hello\\x1\\xaa\\xfe\\xed”);
对于(尺寸i=0;i

请注意,
main()
中的测试“driver”将在您的情况下被替换,您希望将例如
argv[1]
传递到
decode()
。双反斜杠保护了C编译器,我们真的希望得到一个包含反斜杠转义的字符串。

使用bash或任何其他shell都不可能将零字节传递给程序参数。这只是因为在C标准中是不可能的

C标准说明(强调矿山):

。。。主功能的参数应遵守以下约束:
-…
-如果argc的值大于零,则数组成员argv[0]到argv[argc-1]应包含指向字符串的指针,这些字符串在程序启动之前由主机环境给定实现定义的值
-

“字符串”是(强调我的):

字符串是以
结尾的连续字符序列,包括第一个空字符。。。字符串的长度是空字符前面的字节数,字符串的值是包含字符的值的顺序

“空字符”是所有位都设置为0的
字节。它是零。字符串在第一个“空字符”处终止。如果一个字符数组中嵌入了零字节,那么它就不能是字符串(嘿,确切地说,请参见,字符串文字可能不是字符串,因为它可以嵌入空字符)。不能将参数中嵌入的多个
0x00
值传递给C程序,因为传递的不是“字符串”

正确的方法是围绕它编写自己的解析器,它将接受“字符串”(即
/a.out“002C0021”
)并自己转换为零字节

对于您的用例,如果它很简单,我可以在另一个答案中给出一个更简单的解析器。例如,您可以在程序中传递一个所有字节都递增1,然后递减1的参数

或者您可以传递特殊的字节值,比如ex.
0xff
(如果您的实现和操作系统及环境支持传递
0xff
字节),以代替
0x00
,并在程序中替换它们。该选项如下所示:

#include <string.h>
#include <stddef.h>
#include <assert.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
   assert(argc >= 2);
   for (size_t i = 0, max = strlen(argv[1]); i < max; ++i) {
        // replace all 0xff by 0x00
        if ( (0xff & argv[1][i]) == 0xff) {
           argv[1][i] = 0x00;
        }
   }
   // use argv[1]
   for (size_t i = 0, max = 4; i < max; ++i) { 
       printf("argv[1][%d] = 0x%02x\n", i, 0xff & argv[1][i]);
   } 
}
经过测试


bash将
$'…'
解释为。
\xff
被解释为十六进制常量,因此第一个参数将等于
(char[]){0xff,0x2c,0xff,0x2c,0x00}
。用
0x00
替换
0xff
后,它将变成
(char[]){0x00,0x2c,0x00,0x2c,0x00}
并且可以使用前4个字节。

这个字符串应该被编码为UTF-16还是类似的东西?它肯定不是以
\0
结尾的C字符串。如果您在Windows上工作,那么在命令行上支持宽字符的解决方案是使用
int-wmain(int-argc,wchar\u t*argv[])
您需要将字节序列作为参数传递,还是让程序从标准输入读取它?对于后者,您可以执行
/a.out是的,我需要将字节序列作为参数传递。这就是类似的事情的用途:使用受限字符集对任意二进制数据进行编码。即使您可以使用
$“…”
语法和智能转义在bash命令行上以字符串形式传递几乎任意字节,这有其局限性。特别是,bash的内部字符串表示不能处理零字节(因为bash的C字符串零终止)。您永远不能将零字节从bash传递到任何地方,因为bash不像许多命令行工具那样在内部“允许”零字节。最好使用
printf
(和consort)生成零并将它们直接导入程序。对于bash,它应该是
/myprogram$'\x00\x2c\x00\x21'
。那么就不需要解析了。@alk-Uh,但是字符串中不能有0个字符,所以
argv[1]
的值非常奇怪。它不是字符串数据,必须由应用程序从外部字符串表示形式解析。刚刚测试了这个,结果我给出了错误的建议,就像每次传递
$'\x00\x2c\x00\x21'
时一样
#include <string.h>
#include <stddef.h>
#include <assert.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
   assert(argc >= 2);
   for (size_t i = 0, max = strlen(argv[1]); i < max; ++i) {
        // replace all 0xff by 0x00
        if ( (0xff & argv[1][i]) == 0xff) {
           argv[1][i] = 0x00;
        }
   }
   // use argv[1]
   for (size_t i = 0, max = 4; i < max; ++i) { 
       printf("argv[1][%d] = 0x%02x\n", i, 0xff & argv[1][i]);
   } 
}
./a.out $'\xff\x2c\xff\x2c'