执行此代码后:
char **argv_p;
char *argv[20] = { NULL };
memcpy(&argv_p, &argv, sizeof(argv_p));
argv_p
最终为NULL。
这是因为& argv正在分解为指向argv数组中第一个指针的指针。使用&argv[0]
会产生相同的结果(如预期的那样)。
问题是,C中是否存在允许将char ***
传递给memcpy的语法,而不会诉诸像hacky这样的东西
char **argv_p;
char *argv[20] = { NULL }, **argv_start = argv;
memcpy(&argv_p, &argv_start, sizeof(argv_p));
我测试过并产生了正确的结果。
编辑:我知道你可以直接分配,但这是为了解决const问题。如果有人知道为什么execve
采用char * const *
而不是char const **
作为其第二个参数,则可以获得互联网积分。
修改编辑:为了澄清,有争议的区别:
char * const *
- 使数组的内容不可变
char const **
- 使数组指向的字符串缓冲区的内容为immutable。
Const总是恭维左边的东西,除非它首先出现(ANSI C的家伙需要射击),在这种情况下它会在右边的东西上作出判断。虽然很多人写const char *
,但有些人认为最好的做法是编写char const *
,因为const的应用是一致的。
如果没有收到C编译器的警告,你就不能抛弃const。 memcpy是在没有警告的情况下解决此问题的唯一方法。
许多较旧的库没有正确地将其函数的参数标记为const,如果已将const正确应用于代码中的类型,则编译器将发出警告。这就是使用memcpy偶尔可以接受的原因。
答案 0 :(得分:0)
不要尝试通过复制指针来解决const
。
相反,可能需要复制指针所指向的数据,然后您可以使用非const指针指向非const数据,并且所有这些数据都适用于编译器和优化器。
别名指针以避免使用限定符永远不会被接受,无论如何完成,即将指针复制到具有不同限定符的变量甚至不是好习惯,在某些情况下甚至可能导致运行时错误或其他未定义的行为(例如,在const
限定符导致引用的存储为只读,并且别名(ab)用于尝试实际修改存储的情况下。
应尽可能删除限定符"上游"避免与可能不接受带限定符的参数的系统库造成不必要的冲突(C当然并不总是允许这种可能性)。
在绝对必要的地方,以及可以证明不会导致问题的地方,可以使用__UNCONST()
宏。如果目标平台的编译器没有提供,那么最好的解决方案是将__UNCONST()
定义为无操作,并记录可能导致可能接受的潜在警告(并说明原因)。
答案 1 :(得分:0)
在execve中,argv
可以声明为char *const argv[]
并向后读取它是一个常量字符串数组,但该数组是可变的,可以更改为包含不同的常量字符串。在老式的Unix系统中,C main函数可以带3个参数,第三个参数就像execve一样是环境数组。在main()中,如果你正确地修改了argv(例如,将元素设置为""
,直到你遇到终止NULL),你可以阻止ps
命令显示已传递给它的命令行参数你的计划。通过设置argv[0]="foo"
,命令将显示为" foo"是可执行文件的名称。例如,如果您的命令将密码作为命令行参数,那么在新奇的Linux系统上将其隐藏起来ps
或/proc/PID/cmdline
是明智的。有关如何在新奇的Linux系统中执行相同操作,请参阅http://netsplit.com/hiding-arguments-from-ps。