memcpy a int to a char buffer ?

J

Juergen Wohnich

Hello,
i want to do store int variablen into a char Buffer.
Like this:

char Buffer[1024];
int b = 1447;
int *pb; // pb deklariert als pointer auf int
pb = &b; // & ist Adress operator, liefert Adresse von b
memcpy( Buffer, pb, 4 );

This seem to work but now i want to copy the int Variable to another
position in the buffer. How do i this ?
This causes a error:

char Buffer[1024];
int b = 1447;
int *pb; // pb deklariert als pointer auf int
pb = &b; // & ist Adress operator, liefert Adresse von b
memcpy( Buffer[100], pb, 4 ); // cause: error C2664: 'memcpy' : cannot
convert parameter 1 from 'char' to 'void *'

How can i do this ?
 
J

Jim Langston

Juergen Wohnich said:
Hello,
i want to do store int variablen into a char Buffer.
Like this:

char Buffer[1024];
int b = 1447;
int *pb; // pb deklariert als pointer auf int
pb = &b; // & ist Adress operator, liefert Adresse von b
memcpy( Buffer, pb, 4 );

This seem to work but now i want to copy the int Variable to another
position in the buffer. How do i this ?
This causes a error:

char Buffer[1024];
int b = 1447;
int *pb; // pb deklariert als pointer auf int
pb = &b; // & ist Adress operator, liefert Adresse von b
memcpy( Buffer[100], pb, 4 ); // cause: error C2664: 'memcpy' : cannot
convert parameter 1 from 'char' to 'void *'

How can i do this ?

To answer the error you are getting, Buffer[100] is the char at position
101. You just want the address of this or
&Buffer[100].
 
H

Henryk

you can do some casting to get the same result

*(reinterpret_cast<int*>(&Buffer[the_position_you_want_to_start])) = n;

Some comments:
- get char pointer with &Buffer[the_position_you_want]
- cast this point to int pointer with reinterpret_cast<int*>(...)
- set the value at that pointers address with *(...) = b
 
A

Andre Kostur

you can do some casting to get the same result

*(reinterpret_cast<int*>(&Buffer[the_position_you_want_to_start])) = n;

Some comments:
- get char pointer with &Buffer[the_position_you_want]
- cast this point to int pointer with reinterpret_cast<int*>(...)
- set the value at that pointers address with *(...) = b

Oh no you can't.... (not according to the Standard anyway). Try it on the
Sparc platform for example. If the_position_you_want doesn't result in a
correctly aligned memory access for deferencing that pointer... your
program will crash (one possible result for the Undefined Behaviour that
was invoked).
 
H

Henryk

Ok, that is new to me.

We have Sparc Leons inhouse. But it is too long ago that I worked with
to remember...

Just for my interest:

Could you give some more explanation why it would crash? Must an
integer value 2- or 4-byte aligned in memory? What about derefencing
the pointer back to char? Are there any alignment constraints then?
What about 1-byte packed structures?
 
A

Andre Kostur

Ok, that is new to me.

We have Sparc Leons inhouse. But it is too long ago that I worked with
to remember...

Just for my interest:

Could you give some more explanation why it would crash? Must an
integer value 2- or 4-byte aligned in memory? What about derefencing
the pointer back to char? Are there any alignment constraints then?
What about 1-byte packed structures?

As I recall, due to the instruction set on the processor, it can't
load/store an int-sized chunk of memory into a register from an unaligned
memory address.

So, with the example:

char buffer[1024];

*(reinterpret_cast<int *>(&buffer[1])) = 2;

The compiler may emit the machine code to load 2 into a register, then
attempts to store the register into the memory address &buffer[1]. The
hardware doesn't allow it, so the CPU generates a trap. This ends up
manifesting itself as a bus error in your program, and your program
crashes.

Accessing an int inside a 1-byte packed structure isn't an issue since
the compiler can examine your int access and realize that since it is
accessing the int from an unaligned address it will emit the machine code
to do the extra memory accesses (in order to comply with the aligned
memory access rules) to compose the int. So if you had (assuming
whatever compiler magic to make it 1-byte aligned):

struct st
{
char ch;
int anInt;
};

st stVar;
char * overlay = reinterpret_cast<st *>(&stVar);

In the example above it reads the 4 bytes starting at &overlay[0] into a
register, left shifts it 8 to throw away the 1st byte, then load the byte
at &overlay[4] and bitwise-or it with the working register to finally get
the complete int. Note that &stVar is by definition correctly aligned
for an object of type st.

To bring this discussion back to the Standard realm (from Sparc-
specific), the original code has undefined behaviour because you're
casting a pointer between unrelated types (and not void*).

What does work:

char buffer[1024];
int someInt(2);

memcpy(&buffer[1], &someInt, sizeof(someInt));

memcpy has to be able to deal with unaligned memory copies, so this would
work. (Exactly how it works is the problem of the compiler implementor,
as well as any sort of optimizations)
 
H

Henryk

Ok, thank you. Got your point.

About the undefined behavior:

I thought the purpose of reinterpret_cast is to tell the compiler "shut
up I know what I do", which is true sometimes...

I do this cast pretty often. For instance to extract data from a byte
stream. Suppose the byte stream contains a float value somewhere
(possibly bytes had to be swapped before fron sender/receiver because
of endian mismatch). This cast is the most efficient way to extract the
data.

The overhead of memcpy for only a few bytes (8 for float) is just too
much.

It worked so far but good to know the pifalls at some machines as you
pointed it out.

Greets
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top