Compose an array with 2byte+1byte+2byte

Considering that an char* array, char* head = new char[5], must be filled with three values:

1
2
3
short start = 0xEB90;  // 2 bytes
char = 0x02;           // 1 byte
short lenght = 0;      // 2 bytes 

How to proceed in this endeavour?

Is it a good idea to do:

1
2
memset(header,'0xEB90',2);
header[2] = id;

But, how to add the last part (which was called lenght utilizing the short type just because it match with the size required)?

Thanks in advance.
Last edited on
closed account (zb0S216C)
What you're trying to do is implementation-specific because the size of "short" can vary on different systems. It would be better if you did this:

 
char *head( new char[( ( 2 * sizeof( short ) ) + sizeof( char ) )] );

The above code will always guarantee that your array will hold 2 "short int"s and 1 "char". As for adding data into that array, you'd have to interpret an address within the array as a specific type then write to that address. For example:

1
2
3
4
5
6
7
8
9
10
union MultiPointer
{
    short *Short_;
    char *Byte_;
};

MultiPointer Pointer_;
Pointer_.Byte_ = head;
*Pointer_.Short_ = short( 1 );
*( Pointer_.Byte_ + sizeof( short ) ) = 'W';

Get the idea?

Wazzak
I think you meant to use memcpy instead of memset. It's a good idea.
The only thing you need is to keep track of the number of bytes you've written.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char* head = new char[5];
short start = 0xEB90;
char mychar= 0x02;
short length = 0;
   
unsigned int WrittenBytes = 0;
   
memcpy( &head[WrittenBytes], &start, sizeof(start) );
WrittenBytes += sizeof(start);
    
memcpy( &head[WrittenBytes], &mychar, sizeof(mychar) );
WrittenBytes += sizeof(mychar);
    
memcpy( &head[WrittenBytes], &length, sizeof(length) );
WrittenBytes += sizeof(length);
Another idea:

1
2
3
4
5
6
7
typedef struct {
    short start;
    char id;
    short lenght;
} Head;
Head head1;
char *head = (char *)&head1


Is it a good approach?
Last edited on
C'mon. It's C++. Quit abusing unions and using C-style casts. Get creative!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <stdexcept>
#include <memory>
#include <type_traits>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <limits>

class bytes
{
public:
    typedef std::uint8_t byte_type ;

    bytes(unsigned size) 
        : _size(size), _mem(new byte_type[size]) {}

    template <typename T>
    void store(unsigned index, T value, 
        typename std::enable_if<std::is_trivial<T>::value >::type* = 0)
    { 
        _check(index, sizeof(T)) ;
        *reinterpret_cast<T*>(&_mem[index]) = value ; 
    }

    template <typename T>
    T retrieve(unsigned index, 
        typename std::enable_if<std::is_trivial<T>::value >::type* = 0) const
    {
        _check(index, sizeof(T)) ;
        return *reinterpret_cast<T*>(&_mem[index]) ; 
    }

    unsigned size() const { return _size; }

    operator byte_type*() { return _mem.get(); }
    
    byte_type operator[](const unsigned index) const
    {
        _check(index, sizeof(_mem[0])) ;
        return _mem[index]; 
    }

private:

    void _check( unsigned index, unsigned size ) const
    {
        if ( index + size > _size )
            throw std::logic_error("bytes: Out of range!") ;
    }

    const unsigned _size ;
    std::unique_ptr<byte_type[]> _mem ;
};

std::int16_t start  = 0xEB90 ;
std::int16_t length = 0 ;
std::int8_t  id =  2 ;

const unsigned offset[] = { 0, sizeof(start), sizeof(start)+sizeof(id) } ;

int main()
{
    bytes myBytes(5) ;

   try 
   {
        myBytes.store(offset[0], start) ;
        myBytes.store(offset[1], id) ;
        myBytes.store(offset[2], length) ;
        // myBytes.store(offset[2], 39LL) ; // exception thrown

        std::cout << std::hex << myBytes.retrieve<int16_t>(offset[0]) << '\n' ;
        std::cout << static_cast<int>(myBytes.retrieve<int8_t>(offset[1])) << '\n' ;
        std::cout << myBytes.retrieve<int16_t>(offset[2]) << '\n' ;
   }   

   catch(std::exception& ex)
   {
       std::cerr << ex.what() << '\n' ;
   }
}

closed account (zb0S216C)
@cire: Please, tell me, what is not an abuse of "union"? </sarcasm > Also, you're code is good... if you like unnecessary complexity of a simple problem. Besides, the OP clearly stated that he/she will be using "short" and "char" as the target types; there's not need to bring templates into this.

Wazzak
Last edited on
Please, tell me, what is not an abuse of "union"?


One might start with uses that aren't using undefined behavior to avoid a simple cast. </sarcasm>


Also, you're code is good... if you like unnecessary complexity of a simple problem.Besides, the OP clearly stated that he/she will be using "short" and "char" as the target types; there's not need to bring templates into this.


I know right. Who would design code for a general case instead of a specific case? I mean, it's pretty well known that code should never be reused and requirements never change.

requirements never change.


It's my experience that customers go to great lengths to help with this by ensuring they never actually provide any requirements in the first place. It they don't exist, they can't change :)
Pointer casting is a dangerous solution.
Some systems will crash if you dereference an address that is not properly aligned wrt its type.
That's a good point. I had in mind integral types and bit shifting in the original code, but that wouldn't work with arbitrary types, and I kind of threw that code out there. A correct implementation would have store and retrieve functions that looked more like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    template <typename T>
    void store(unsigned index, T value, 
        typename std::enable_if<std::is_trivial<T>::value >::type* = 0)
    { 
        _check(index, sizeof(T)) ;

        byte_type * source = reinterpret_cast<byte_type*>(std::addressof(value)) ;
        for ( unsigned i=0; i < sizeof(T) ; ++i )
            _mem[index+i] = *source++ ;
    }

    template <typename T>
    T retrieve(unsigned index, 
        typename std::enable_if<std::is_trivial<T>::value >::type* = 0) const
    {
        _check(index, sizeof(T)) ;

        T value ;
        byte_type * dest = reinterpret_cast<byte_type*>(std::addressof(value)) ;
        for ( unsigned i=0; i < sizeof(T) ; ++i )
            *dest++ = _mem[index+i] ;

        return value ;
    }


And certainly using memcpy in place of the for loops would work.
Topic archived. No new replies allowed.