2

What I am trying:

BYTE test[] = {0x00,0x00,0x00,0x00};
*(test+1) = 0xFFFF;

What I get:

00000000 11111111 00000000 00000000

What I expect or want to achieve:

00000000 11111111 11111111 00000000

Background: In one part of my program I need to insert a WORD into a part of an array. Yes, normally I could just do

*(test+1) = 0xFF;
*(test+2) = 0xFF;

but I wonder if there is a possibility to do this as a one-liner like in the first example. Memcpy is no option here since I would need to allocate space for a second array.

Kntlii
  • 157
  • 6
  • 1
    The short answer is 'no'. The long answer involves type-punning through unions. Unless, that is, you really are just trying to set the values as Alok Singhal showed in his answer using memset. – Christian Gibbons Feb 21 '19 at 19:44
  • 1
    @IłyaBursov That breaks strict aliasing and is undefined behavior. – Christian Gibbons Feb 21 '19 at 19:45
  • @ChristianGibbons isn't byte exception from this rule? – Iłya Bursov Feb 21 '19 at 19:47
  • I was about to say 'no' unless you play with types and such, but since @ChristianGibbons already said it, so I'm not gonna say it now :D – sid-m Feb 21 '19 at 19:47
  • "Memcpy is no option here since I would need to allocate space for a second array." This makes little sense. First, paraneters to `memcpy` need not be arrays, an address of a single integer will do. Second, if you for some reason do need a second array (you don't but let's pretend), it would be of whoppin' two elements. Allocating such an array on the stack is not a problem. – n. m. could be an AI Feb 21 '19 at 19:47
  • 1
    @IłyaBursov It is a one-way street (and technically it's character types, so `char`, `signed char`, and `unsigned char` specifically). Character-types can alias any other type, but not the other way around. – Christian Gibbons Feb 21 '19 at 19:48
  • `memset` is your friend but … why? why not write the code simple and easy to understand - like: `test[1]=0xff; test[2]=0xff;` done... easy to write - easy to understand. If you need to set many elements then `memset` is good. Alternatively make a `for`-loop – Support Ukraine Feb 21 '19 at 19:52

4 Answers4

5

For this case, memset(test+1, 0xFF, 2) should work.

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
  • Excellent! Good compilers will generate a single instruction on x86 targets, as can be seen on https://gcc.godbolt.org/z/WmgIjo . Unaligned writes are OK on these targets for most OSes. – chqrlie Feb 21 '19 at 20:05
5

Your options are

  1. test[1] = 0xFF;
    test[2] = 0xFF;
    
  2. memset(test + 1, 0xFF, 2);
    
  3. const char bytes[2] = {0xFF, 0xFF};
    memcpy(test + 1, bytes, 2);
    
  4. uint16_t value = 0xFFFF;     // beware of byte order
    memcpy(test + 1, &value, 2);
    
  5. memcpy(test + 1, (const unsigned char []){0xFF, 0xFF}, 2));
    
  6. or any other code that addresses the individual bytes separately.


What is not an option is:

*(uint16_t)&test[1] = 0xFFFF;

The reason is simple: it breaks two rules in C: strict aliasing and alignment. What is worse is that you can get away with this in this part of code, but dereferencing unaligned uint16_t pointers is never safe, even on x86-64 that supposedly supports unaligned accesses

-1
#define modify(dest,src,pos)    do { unsigned char *tmp =(void *)&dest; memcpy(tmp + pos,&src, sizeof(src));}while(0)

void *modify1(void *dest, void *src, size_t pos, size_t len)
{
    unsigned char *tmp = dest;
    memcpy(tmp + pos, src, len);
    return tmp + pos;
}

examples:

char x[10];
short y = 0xffff;
modify(x,y,3);

or modify1(x,&y, 3, sizeof(y));

Note that the macro one will not work in all circumstances.

0___________
  • 60,014
  • 4
  • 34
  • 74
-2

The following code is a generic solution that let you write a value of 2 Bytes (16 bits) into successive cells of an array :

uint16 data = 0xFFFF;

BYTE test[] = {0x00,0x00,0x00,0x00};
*(test+1) = data & 0xFF;
*(test+2) = data >> 8;

The result will be:

00000000 11111111 11111111 00000000

So just change the value of data.

aminosbh
  • 193
  • 1
  • 5