简体   繁体   English

如何使用memcpy将指针复制到数组的元素

[英]How to copy a pointer to an element of an array with memcpy

After executing this code: 执行此代码后:

char **argv_p;
char *argv[20] = { NULL };

memcpy(&argv_p, &argv, sizeof(argv_p));

argv_p ends up being NULL. argv_p最终为NULL。

This is because &argv is decomposing into a pointer to the first pointer in the argv array. 这是因为&argv分解为指向argv数组中第一个指针的指针。 Using &argv[0] yields identical results (as expected). 使用&argv[0]产生相同的结果(如预期)。

Question is, whether there's syntax in C that would allow a char *** to be passed to memcpy, without resorting to something hacky like 问题是,C语言中是否存在允许将char ***传递给memcpy的语法,而无需诉诸于像

char **argv_p;
char *argv[20] = { NULL }, **argv_start = argv;

memcpy(&argv_p, &argv_start, sizeof(argv_p));

Which I have tested and produces the correct result. 我已经测试并产生了正确的结果。

Edit: I know you can do straight assignment, but this is for working around const issues. 编辑:我知道您可以直接分配,但这是为了解决const问题。 Bonus internet points if anyone knows why execve takes a char * const * instead of a char const ** as its second argument. 如果有人知道execve为什么将char * const *而不是char const **作为第二个参数,则execve额外的互联网积分。

Edit Edit: To clarify, the difference between the consts: 编辑编辑:澄清一下,const之间的区别:

char * const * - makes the contents of the array immutable char const ** - makes the contents of the string buffers pointed to by the array immutable. char * const * -使数组的内容不可变char const ** -使数组指向的字符串缓冲区的内容不可变。

Const always constifies the thing to the left, unless it appears first (the ANSI C guys need shooting for that) in which case it constifies the thing on the right. const总是将事物表示在左侧,除非它首先出现(ANSI C的家伙需要为此射击),在这种情况下,它表示事物在右侧。 Although many people write const char * , it's considered best practice by some, to write char const * because then application of the const is consistent. 尽管很多人都写const char * ,但有人认为这是最佳实践,因为写char const *原因在于char const *应用是一致的。

You can't cast away a const without receiving a warning from the C compiler. 如果不从C编译器收到警告,则不能放弃const。 memcpy is the only way to work around this without warnings. memcpy是解决此问题的唯一方法,而不会发出警告。

Many older libraries don't correctly mark arguments to their functions as const, and if you have applied const correctly to types in your code, the compiler will emit warnings. 许多较旧的库没有正确地将其函数的参数标记为const,并且如果您已将const正确地应用于代码中的类型,则编译器将发出警告。 That is why using memcpy is occasionally acceptable. 这就是为什么偶尔使用memcpy的原因。

Do not try to work around const by copying a pointer. 不要尝试通过复制指针来解决const

Instead it may be necessary to copy the data the pointer points to, and then you can point to the non-const data with a non-const pointer and all will be well with the compiler and optimizer. 相反,可能有必要复制指针指向的数据,然后可以使用非常量指针指向非常量数据,并且编译器和优化器都可以正常工作。

Aliasing a pointer to avoid qualifiers is never really acceptable, no matter how it is done, ie copying a pointer to a variable with different qualifiers is even not good practice, and in some cases may even cause runtime errors or other undefined behaviour (eg in the case where a const qualifier causes the referenced storage to be read-only, and the alias is (ab)used to try to actually modify the storage). 别名指针避免限定符从来都不是真正可以接受的,无论如何完成,即,将指针复制到具有不同限定符的变量甚至都不是一种好习惯,并且在某些情况下甚至可能导致运行时错误或其他未定义的行为(例如, const限定词导致所引用的存储为只读,并且别名被(试图用于实际修改存储)的情况。

Where possible qualifiers should be removed "upstream" to avoid causing unnecessary clashes with system libraries that may not accept parameters with qualifiers (C of course does not always allow for this possibility). 应尽可能在上游删除限定符,以避免与可能不接受限定符参数的系统库造成不必要的冲突(当然C并不总是允许这种可能性)。

Where absolutely necessary, and where it can be shown to not cause problems, it is acceptable to use an __UNCONST() macro. 在绝对必要的地方,并且可以证明没有问题的地方,使用__UNCONST()宏是可以接受的。 If the compiler for the target platform does not offer one then the best solution is to define __UNCONST() as a no-op and to document the potential warning that may result as acceptable (and show why). 如果目标平台的编译器不提供编译器,则最佳解决方案是将__UNCONST()定义为无操作,并记录可能导致可接受的潜在警告(并说明原因)。

In execve, argv can be declared as char *const argv[] and reading this backwards it is an array of constant strings, but the array is mutable and can be changed to include different constant strings. 在execve中,可以将argv声明为char *const argv[]并向后读取,它是一个常量字符串数组,但是该数组是可变的,可以更改为包含不同的常量字符串。 In old-fashioned Unix systems, the C main function could take 3 arguments, the third argument is the environment array just like execve. 在老式的Unix系统中,C main函数可以带有3个参数,第三个参数与execve一样是环境数组。 In main(), if you modified argv properly (eg, setting elements to "" until you run into the terminating NULL) you could prevent the ps command from displaying the command line parameters that had been passed to your program. 在main()中,如果您正确修改了argv(例如,将元素设置为""直到遇到终止NULL),则可以防止ps命令显示已传递给程序的命令行参数。 By setting argv[0]="foo" , the command would show up as if "foo" were the name of the executable. 通过设置argv[0]="foo" ,该命令将显示为“ foo”是可执行文件的名称。 For example, if your command took a password as a command line parameter, it would be prudent to hide it from ps or maybe /proc/PID/cmdline on newfangled Linux systems. 例如,如果您的命令将密码作为命令行参数,则在新的Linux系统上将其从ps/proc/PID/cmdline隐藏是明智的。 See http://netsplit.com/hiding-arguments-from-ps for how to do the equivalent thing in a newfangled Linux system. 有关如何在新式Linux系统中执行等效操作的信息,请参见http://netsplit.com/hiding-arguments-from-ps

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM