40

I want to pass in a hardcoded char array as the source parameter to memcpy ... Something like this:

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

This compiled with clang gives the following error:

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

If i modify it to be (see the extra parenthesis ):

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

the error given by clang is:

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);

So, the question:

How do I pass in a hardcoded array as the source parameter of memcpy (http://www.cplusplus.com/reference/cstring/memcpy/)

I have tried:

(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)

and some more insane combinations I'm shamed to write here ...

Please remember: I do NOT want to create a new variable to hold the array.

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167

4 Answers4

44

If you use C99 or later, you can use compound literals. (N1256 6.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;
}

UPDATE: This worked for C++03 and C++11 on GCC, but are rejected with -pedantic-errors option. This means this is not a valid solution for standard 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;
}

points are:

  • Make the array const, or taking address of temporary array will be rejected.
  • Cast numbers to char explicitly, or the narrowing conversion will be rejected.
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
25

You can just send a string as parameter. It seems to compile just fine.

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

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

    return 0;
}
Igal S.
  • 13,146
  • 5
  • 30
  • 48
  • 1
    If you must initialize `dest` at all (which is questionable), you should use `'\0'` rather than `0`... – Mikhail T. Mar 02 '16 at 11:31
  • 1
    You are right. I copied the entire example from the OP ideone example. I just changed the `memcpy` line. – Igal S. Mar 02 '16 at 12:08
  • 3
    @MikhailT. where's the difference between `'\0'` and `0`? They both compile to the same `0` value for me. – rev Mar 02 '16 at 15:18
  • @AcidShout It's the same. Sometimes it is more understandable to use `'\0'`. However I think everyone understands what the code is doing. – Konstantin W Mar 02 '16 at 16:20
  • 2
    @NateEldredge: Wouldn't `strcpy` copy the trailing null? – user2357112 Mar 02 '16 at 19:08
  • @AcidShout, I'm pretty sure, `'\0'` might *not* equate to `0` on some esoteric platform. The same way `NULL` is not always the same as `0` either. @user2357112, yes, `strcpy` will copy the trailing `'\0'` -- and so would `memcpy`, if the hard-coded length were bumped from 5 to 6. But the asker didn't say anything about `dest` needing to end up a proper C-string, so this is all uncalled for. – Mikhail T. Mar 02 '16 at 19:52
  • @MikhailT. [C11 5.2.1](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=40) the null character is "A byte with all bits set to 0". (to pre-empt the next question: [6.2.6.2](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=63)) – Alex Celeste Mar 02 '16 at 21:57
  • 1
    @MikhailT. By the way, `NULL` must always evaluate to a zero: " An integer constant expression with the value 0, or such an expression cast to type `void *`, is called a null pointer constant" (6.3.2.3:3); "the [`stddef.h`] macros are: `NULL`, which expands to an implementation-defined null pointer constant…" (7.19:3). So the only bit that's implementation-defined is whether it's `0` or `((void *) 0)`. – wchargin Mar 03 '16 at 03:28
  • @WChargin, is there any telling, what the casting to `void *` might do to an innocent integer `0`? @Leushenko, yes, you are right. Still, `\0` seems clearer, when operating on `char`s... – Mikhail T. Mar 03 '16 at 04:46
  • @MikhailT. I believe you might be [mixing up null pointers with the NULL macro](http://stackoverflow.com/questions/32136092/how-to-write-c-c-code-correctly-when-null-pointer-is-not-all-bits-zero/32136460#32136460). – Lundin Mar 03 '16 at 07:48
  • @MikhailT.: please don't give advices if you don't know what the ` = {0};` is actually doing. This is pretty much correct and also (while anyway doing the same) the correct version over doing `\0`! – dhein Mar 03 '16 at 11:13
  • Why do you need to initialize an array if you're just going to overwrite it on the next line with `memcpy`? And why did you change the size to `[6]`? – Barmar Mar 08 '16 at 19:35
  • @Barmar - As I said before. You are all right, and there is no need to initialize the array at all. I copied the example as is from the original example of the OP. And just modified a single line of `memcpy` to show the correct answer the the question. – Igal S. Mar 09 '16 at 07:10
20

The best solution is not to do this at all, but to use a temporary variable:

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

This code is the most maintainable, because it contains no "magic numbers", so it will not contain any missing array item or array-out-bounds bugs, like the compound literal version could.

This code is also compatible with C++ and C90.

The most important thing here is to realize that the generated machine code will be identical anyway. Don't think you are doing any form of optimization by using compound literals.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    Of particular note -- if this is what the OP is worried about -- this uses no more memory than embedding the array in the `memcpy` call. – TripeHound Mar 02 '16 at 12:30
  • 3
    -1, OP explicitly said he does not want to do this in his original post. Advising someone to do something the "right" way after they specifically said it would not work in their fringe case undermines the core problem. – user1717828 Mar 02 '16 at 13:17
  • 10
    @user1717828 well, for argument's sake, I would say there's a difference between saying something won't work in a particular fringe case and saying they simply don't want to do it. As far as I can tell from the question, the latter is the case here. And it's often - not always, but often - the case that when someone says "I don't want to do X", they really should be doing X anyway, they're just mistaken or misguided about the reason why they think they shouldn't be doing it. – David Z Mar 02 '16 at 13:40
  • 13
    @user1717828 One of the most important tasks in any form of engineering is to question the specification, particularly when it doesn't make any sense. In this case, the specification (OP) suggests that the poster may not be aware of how variables are allocated in memory or how compiler optimizations work. It is therefore important to post a "counter-answer", or otherwise beginners might read this post and think that the "no variable" requirement in the question makes sense, then start to obfuscate their code accordingly, by spamming compound literals all over it. – Lundin Mar 02 '16 at 13:56
  • 4
    @DavidZ You are right but from a 13K user I'd consider that "I do not want to do X" is a sentence we can trust. – LPs Mar 02 '16 at 13:57
  • 3
    @LPs That's a reasonable point, but I don't really agree - I wouldn't suggest even trusting myself if I ask a question with a sentence like that. If there's an obvious solution and the asker doesn't want to use it, they should give some sort of justification in the question. (As little as "educational purposes" is fine, but just "I don't want to" is not, for me.) Otherwise I think it's legitimate to answer that they should just do the thing they don't want to do, if that's what you really think the right answer is. – David Z Mar 02 '16 at 14:06
  • "_because it contains no "magic numbers", so it will not contain any missing array item or array-out-bounds bugs, like the compound literal version could_" -- But the compound literal version doesn't use 'magic numbers' as well. Also, how are compound literals prone to 'missing array item' and 'array-out-of-bounds' bugs? – Spikatrix Mar 02 '16 at 14:18
  • 7
    Arguing that we should trust a statement because they're from a 13K user is the logical fallacy "Argument from Authority". Just because someone with a good reputation (in any field) makes a claim doesn't mean they're right. – Hank Schultz Mar 02 '16 at 14:20
  • 3
    @CoolGuy `memcpy(dest, (char[]){0xE3,0x83,0xA2,0xA4,0xCB} ,5);` <-- Here's the magic number. You can't use `sizeof` on the compound literal. Well, you can, if you use a macro, which would perhaps be the worst option of all: `#define COMPOUND (char[]){0xE3,0x83,0xA2,0xA4,0xCB}` ...`memcpy(dest, &COMPOUND , sizeof(COMPOUND));` which is just a completely brain-damaged solution, compared to using a plain const variable. – Lundin Mar 02 '16 at 14:24
  • 1
    Doing some tests, it looks like you get better code by declaring `src` as `static`. Without `static`, my compiler does things like hardcoding a bunch of single-byte immediate loads, or creating the array on the stack at every function call. – Nate Eldredge Mar 02 '16 at 15:04
  • @NateEldredge A good compiler shouldn't do that. Optimizations enabled? The C standard does state that a compound literal should work like a local variable in terms of scope and storage, meaning that without optimizations it should be on the stack. But I would think that a good compiler would optimize that and replace it with a copy-down directly from `.rodata`. – Lundin Mar 02 '16 at 15:22
  • @Lundin: It's gcc 5.2.1 on x86-64 with -O2 or -O3 or -Os. The code in this post, or the same with a compound literal, compiles to 5 x `movb`. Using `static`, we do get an array in `.rodata`, one `movl` and one `movb`. – Nate Eldredge Mar 02 '16 at 15:23
  • 1
    @NateEldredge trivially solved by enclosing the parts between { and } – minexew Mar 02 '16 at 19:21
  • 1
    Note that the OP mentioned in a comment (albeit one that's hidden by default) that he's *trying* to write unreadable code. – bta Mar 02 '16 at 20:45
11

You can use 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;
}
LPs
  • 16,045
  • 8
  • 30
  • 61