【问题标题】:C hardcoded array as memcpy parameterC 硬编码数组作为 memcpy 参数
【发布时间】:2016-06-15 04:44:31
【问题描述】:

我想将硬编码的 char 数组作为 source 参数传递给 memcpy ... 像这样:

memcpy(dest, {0xE3,0x83,0xA2,0xA4,0xCB} ,5);

使用 clang 编译会出现以下错误:

cccc.c:28:14: error: expected expression

如果我将其修改为(请参阅额外的括号):

memcpy(dest,({0xAB,0x13,0xF9,0x93,0xB5}),5);

clang给出的错误是:

cccc.c:26:14: warning: incompatible integer to pointer
              conversion passing 'int' to parameter of
              type 'const void *' [-Wint-conversion]

cccc.c:28:40: error: expected ';' after expression
memcpy(c+110,({0xAB,0x13,0xF9,0x93,0xB5}),5);

那么问题来了:

如何传入一个硬编码数组作为memcpy(http://www.cplusplus.com/reference/cstring/memcpy/)的源参数

我试过了:

(void*)(&{0xAB,0x13,0xF9,0x93,0xB5}[0])  - syntax error
{0xAB,0x13,0xF9,0x93,0xB5}               - syntax error
({0xAB,0x13,0xF9,0x93,0xB5})             - see above
(char[])({0xE3,0x83,0xA2,0xA4,0xCB})     - error: cast to incomplete type 'char []' (clang)

还有一些更疯狂的组合,我很惭愧在这里写...

请记住:我确实想创建一个新变量来保存数组。

【问题讨论】:

  • C 还是 C++?下定决心。
  • memcpy(dest, "\xAB\x13\xF9\x93\xB5",5);
  • @n.m.标题写的是 C,所以我猜是 C。
  • @fritzone 我们要求您澄清语言不是为了惹恼您,而是因为 C 和 C++ 中的答案会有所不同。如果您对两者都感兴趣,请考虑提出两个单独的问题。
  • cccc.c 是我的文件名。 :)

标签: c arrays hardcoded


【解决方案1】:

如果您使用 C99 或更高版本,则可以使用复合文字。 (N12566.5.2.5)

#include <stdio.h>
#include <string.h>
int main(void){
    char dest[5] = {0};
    memcpy(dest, (char[]){0xE3,0x83,0xA2,0xA4,0xCB} ,5);
    for (int i = 0; i < 5; i++) printf("%X ", (unsigned int)(unsigned char)dest[i]);
    putchar('\n');
    return 0;
}

更新:这适用于 GCC 上的 C++03 和 C++11,但被 -pedantic-errors 选项拒绝。这意味着这不是标准 C++ 的有效解决方案。

#include <cstdio>
#include <cstring>
int main(void){
    char dest[5] = {0};
    memcpy(dest, (const char[]){(char)0xE3,(char)0x83,(char)0xA2,(char)0xA4,(char)0xCB} ,5);
    for (int i = 0; i < 5; i++) printf("%X ", (unsigned int)(unsigned char)dest[i]);
    putchar('\n');
    return 0;
}

要点是:

  • 将数组设为const,否则临时数组的取地址将被拒绝。
  • 将数字显式转换为char,否则将拒绝缩小转换。

【讨论】:

  • 有趣的 OP 似乎已经尝试过了——但使用的是 C++ 编译器。
  • 您的更新使您的答案不正确:这是 C++(所有版本)中的非法。如果你的编译器允许,那就错了。
  • 如果您将源设为 unsigned char const[],则不需要所有这些 (char) 演员表。
【解决方案2】:

您可以只发送一个字符串作为参数。似乎编译得很好。

#include <iostream>
#include <string.h>
using namespace std;

int main() {
    char dest[6] = {0};
    memcpy(dest,"\XAB\x13\XF9\X93\XB5", 5);

    return 0;
}

【讨论】:

  • 如果你必须初始化dest(这是有问题的),你应该使用'\0'而不是0...
  • 你是对的。我从 OP ideone 示例中复制了整个示例。我刚刚更改了memcpy 行。
  • @MikhailT。 '\0'0 有什么区别?对我来说,它们都编译为相同的 0 值。
  • @NateEldredge:strcpy 不会复制尾随的 null 吗?
  • @MikhailT。顺便说一句,NULL 的计算结果必须始终为零:“值为 0 的整数常量表达式,或转换为类型 void * 的此类表达式称为空指针常量”(6.3.2.3:3); “[stddef.h] 宏是:NULL,它扩展为实现定义的空指针常量……” (7.19:3)。所以实现定义的唯一位是0 还是((void *) 0)
【解决方案3】:

最好的解决方案是根本不这样做,而是使用临时变量:

const char src[] = {0xE3,0x83,0xA2,0xA4,0xCB};
memcpy(dest, src, sizeof(src));

此代码最易于维护,因为它不包含“幻数”,因此它不会像复合文字版本那样包含任何缺少数组项或数组越界错误。

此代码还兼容 C++ 和 C90。

这里最重要的是要意识到生成的机器代码无论如何都是相同的。不要以为你在使用复合字面量进行任何形式的优化。

【讨论】:

  • -1,OP 在原始帖子中明确表示他不想这样做。在某人明确表示这在他们的边缘情况下不起作用之后,建议他们以“正确”的方式做某事会破坏核心问题。
  • @user1717828 好吧,为了争论,我想说说某事在特定的边缘情况下不起作用和说他们根本不想这样做是有区别的。据我从问题中可以看出,后者就是这种情况。而且经常——不总是,但经常——当有人说“我不想做 X”时,他们真的应该做 X,他们只是错误地或误导了他们认为应该做的原因不要这样做。
  • @user1717828 在任何形式的工程中,最重要的任务之一就是质疑规范,尤其是在它没有任何意义的时候。在这种情况下,规范 (OP) 建议发布者可能不知道变量在内存中的分配方式或编译器优化的工作方式。因此,发布“反答案”很重要,否则初学者可能会阅读这篇文章并认为问题中的“无变量”要求是有道理的,然后开始相应地混淆他们的代码,通过在其上发送复合文字.
  • @DavidZ 你是对的,但对于一个 13K 的用户来说,我认为“我不想做 X”是我们可以信任的一句话。
  • 争论我们应该相信一个声明,因为它们来自一个 13K 用户是逻辑谬误“来自权威的论证”。仅仅因为有良好声誉(在任何领域)的人提出索赔并不意味着他们是对的。
【解决方案4】:

您可以使用Compound Literals

int main()
{
    unsigned char dest[5];
    size_t i;

    memcpy(dest, (unsigned char[]){0xE3,0x83,0xA2,0xA4,0xCB} ,5);

    printf("Test: " );
    for(i=0; i<sizeof(dest)/sizeof(dest[0]); i++)
        printf("%02X - ", dest[i] );
    printf("\n");
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 2015-08-22
    • 2016-02-08
    • 1970-01-01
    相关资源
    最近更新 更多