Struct has different size after being passed to func - c++

I have created a structure with a Id variable and a list of values. When I check the size before passing it to a function as a void* it is 12. Once it gets in the function it is 4. How do I keep the size the same?
Struct Code:
typedef struct
{
int id;
std::list<int> sensorValues;
}dataPacketDef;
Sending to other function code:
void SendDataBufferToServer()
{
cout << "Sending network data size: " << sizeof(dpd) << "\n";
client.writeData((void*)&dpd);
}
In the above function the size is 12 but in the receiving function the size is only 4. The struct is declared as a global variable for my main program.

In the function you are taking the size of a void*, not of a dataPacketDef. And, apparently, on your system sizeof(void*) is 4 bytes. The sizeof operator is simply type-driven: it does not do magical inspection of pointees. In fact, since you have performed type erasure with that antiquated cast, it can't.
You cannot serialise your object in this way. The list isn't flat data; its elements aren't actually part of the dataPacketDef, but dynamically allocated. The list holds pointers to those elements. All you're doing is serialising pointers, which become immediately meaningless on the target system.
Drop this approach entirely and look into how to properly serialise objects in modern C++.

before passing it to a function as a void* it is 12. Once it gets in the function it is 4
Because sizeof pointer in case of your program is 4 bytes, you cant read sizeof struct if you cast instance of your struct to void*. You might fix it by passing to your function also size of your struct ie foo(static_cast<void*>(&myStructObj), sizeof(TypeOfMyStruct)).
[edit]
also as Lightness Races in Orbit pointed out in his answer, serializing std::list is wrong, you will only write pointers to your file/

The size of a pointer is 4 bytes (or 8 if you were using an x64 compiler). If writeData needs to know the size of the pointed-to object, that information will need to be passed to it somehow; a common idiom is to pass the size as a second argument. With that done, you could use a helper function template to simplify things:
template<typename T>
void writeData(Client& client, const T& obj)
{
client.writeData((void*)&obj, sizeof(obj));
}
Although as molbdnilo noted in the question comments, client.writeData() probably still won't be able to do what you want it to due to the presence of a list in dataPacketDef.

This is correct.
A pointer always contains an address, which is 4 bytes on your machine.
Therefore a sizeof any pointer will be 4 bytes on a 32-bit addressing architecture.

sizeof(void*) is 4 bytes on a 32bit machine.

Related

copying array vs copying int cost and performance in c

I am reading a book about c and the following paragraph is a bit unclear for me:
Surprisingly, passing the pointer is not efficient in the above example! That's because of the fact that the int type is 4 bytes and copying it is more efficient than copying 8 bytes of its pointer. But this is not the case regarding structures and arrays. Since copying structures and arrays is done byte-wise, and all of the bytes in them should be copied one by one, it is usually better to pass pointers instead.
as I know all the operations in CPU are limited to arithmetic(plus or minعس) or bit-wise kind of operation so
What does the writer mean about copying array and structure, isn't an int copying a bit shifting operation?
Second: are pointers array?
NOTE: the book name is Extreme C and published by packT
and following example is what the author is referring to:
#include <stdio.h>
void func(int* a) {
int b = 9;
*a = 5; a = &b;
}
int main(int argc, char** argv) {
int x = 3;
int* xptr = &x;
printf("Value before call: %d\n", x);
printf("Pointer before function call: %p\n", (void*)xptr); func(xptr);
printf("Value after call: %d\n", x);
printf("Pointer after function call: %p\n", (void*)xptr);
return 0;
}
'''
The book is not clear and it's also wrong.
The assumption seem to be that an 8 byte pointer is "harder" to copy than a 4 byte integer. That's wrong for nearly all modern CPUs.
Further, the part about copying an array is just plain wrong. That is not what C does. Passing an array in C does not involve an copy. It's actually just like passing a pointer.
The part about structs is however correct... as long as the struct isn't just a simple integer or char but "something bigger".
What does the writer mean about copying array
Sounds like rubbish... as C doesn't pass array by doing a copy
What does the writer mean about copying ... structure,
Structs are copied by value. So passing a struct to a function involves copying every byte of the struct. That is rather expensive if the struct is large.
are pointers array?
No. Pointers are pointers. But... Under the correct circumstances a pointer can be used as an array because *(p + i) is the same as p[i]
What does the writer mean about copying array and structure?
Let's compare two functions taking a large amount of data (e.g. a struct with lots of data members):
void f(const big_type_t* p_big_type);
void g(const big_type_t big_type);
Both can effectively read the values from the caller-specified big_type_t object, but in the former case f() need only be passed a pointer (which is typically 8 bytes on modern everyday hardware) to tell it where the caller has a big_type_t object for it to use. In the latter case g() pass-by-value argument asks the compiler to make a complete copy of the caller's big_type_t argument and copy it to a location on the stack where g() implicitly knows to find it. Every byte of the data in the struct must be copied (unless the compiler's smart enough to optimise under the as-if rule, but that's a bit of a distraction - it's generally best to write code so it's not unnecessarily inefficient if not optimised well).
For built-in arrays, the situation is different. C and C++ implicitly pass arrays by pointer, so...
void h(const int* my_array);
void i(const int my_array[]);
...are both called the same way, with the my_array argument actually being a pointer to the first int the caller specifies.
In C++ there are also std::array<>s, which are effectively struct/classes with a static-sized array data member (i.e. template <typename T, size_t N> struct array { T data_[N]; ... }). They can be passed by-value, the same as structs. So, for large std::array objects, access via a pointer or reference is more efficient than doing a full copy.
Sometimes a function really does want a copy though, as it may need to do something like sort it without affecting the caller-specified variable passed to that argument. In that case, there's not much point passing by pointer or reference.
isn't an int copying a bit shifting operation?
No... the term "bit shifting" has a very specific meaning in programming. Consider an 8-bit integer - say 0x10010110. If we shift this value one bit to the right, we get 0x01001011 - a 0 is introduced on the left, and a 0 is discarded on the right. If we shift the new value to the right again, we could get either 0x00100101 (add 0 at left; discard at right) or - what's called a circular shift or rotation - 0x100100101`, where the right-most bit is moved to become the left-most bit. Bit-shifting happens to CPU registers, and the shifted values can be stored back into the memory where a variable is located, or used in some calculation.
All that's quite unrelated to memory copying, which is where the bits in one value are (at least notionally, without optimisation) copied into "another" value. For large amounts of data, this usually does mean actually copying the bits in a value read from memory to another area of memory.
Second: are pointers array?
No they're not. But, when you have an array, it easily "decays" to a pointer to its first element. For example:
void f(const char* p);
f("hello");
In C++, "hello" is a string literal of type char[6] (as there's implicitly a null character at the end. When calling f, it decays from array form to a pointer to the first character - 'h'. That's usually desirable to give the called function access to the array data. In C++, you can also do this:
template <size_t N> void f(const char(&arr)[N]);
f("hello");
The call above does not involve decay from an array to a pointer - arr is bound to the string literal array and N is derived as 6.
What does the writer mean about copying array and structure, isn't an int copying a bit shifting operation?
When you pass an object of struct type as a parameter in a function, the contents of that structure are copied into the formal parameter:
struct foo {
...
};
void do_something_with( struct foo arg )
{
// do something with arg
}
int main( void )
{
struct foo f = { 1, 2.0, "three" };
...
do_something_with( f );
...
}
The objects main:f and do_something_with:arg are two separate instances of struct foo - when you pass f as an argument, its contents are copied into arg. Any changes you make to the contents of arg do not affect the contents of f.
The thing is, the author of the book is wrong about arrays - when you pass an array expression as an argument to a function, what you are actually passing is a pointer to the first element, not the whole array.
Second: are pointers array?
Arrays are not pointers - however, unless it is the operand of the sizeof or unary & operators, an expression of type "N-element array of T" will be converted, or "decay", to an expression of type "pointer to T" and the value will be the address of the first element of the array.
When you pass an array expression as an argument to a function, what the function actually receives is a pointer to the first element of the array - no copy of the array is made like it is for the struct above.
Finally - while runtime efficiency does matter, correctness, clarity, and maintainability matter more. If it makes sense to pass an argument as a pointer (such as you want the function to modify the argument), then by all means do so. But don't start passing everything as a pointer because it might speed things up. Start by making things clear and correct - then, measure the performance of your code and take action based on that. Most of your runtime performance gains come from using the right data structures and algorithms, not how you pass arguments.
While the sample code has much to be desired and some bugs, I think that the gist of what the author is saying is that for a small data type it is more efficient to directly pass a parameter to a function by value (int) rather than by passing by pointer (int *). When a function is called, parameters are pushed onto the stack and and a type of int would require 2 bytes, but an int *parameter may require 4 or 8 bytes depending on the system.
When passing a struct as a parameter, the overall size of the struct will typically be greater than 4 or 8 bytes, so passing a pointer to thr struct may be more efficient, since only 4 or 8 bytes would need to be copied to the stack.
I am not sure why the author mentioned arrays, since an array cannot be passed to a function by value unless it is contained in a struct.

Recovering structs sent over a network

My coworker wants to send some data represented by a type T over a network. He does this The traditional way™ by casting the T to char* and sending it using a write(2) call with a socket:
auto send_some_t(int sock, T const* p) -> void
{
auto buffer = reinterpret_cast<char const*>(p);
write(sock, buffer, sizeof(T));
}
So far, so good. This simplified example, apart from being stripped of any error-checking, should be correct. Assuming the type T is trivially copyable we can copy values of this type between objects using std::mempcy() (according to 6.7 [basic.types] point 3 in C++17 standard[1]) so I guess write(2) should also work as it blindly copies binary data.
Where it gets tricky is on the receiving side.
Assume the type T in question looks like this:
struct T {
uint64_t foo;
uint8_t bar;
uint16_t baz;
};
It has a field with an alignment requirement of 8 bytes (foo) so the whole type requires a strict alignment of 8 bytes (see example for 6.6.5 [basic.align] point 2). This means that storage for values of type T must be allocated only on suitable addresses.
Now, what about the following code?
auto receive_some_t(int sock, T* p) -> void
{
read(sock, p, sizeof(T));
}
// ...
T value;
receive_some_t(sock, &T);
Looks shady, but should work OK. The bytes received do represent a valid value of type T and are blindly copied into a valid object of type T.
However, what about using raw char buffers like in the following code:
char buffer[sizeof(T)];
read_some_t(sock, buffer);
T* value = reinterpret_cast<T*>(buffer);
This is where my coder-brain triggers a red alert. We have absolutely no guarantee that the alignment of char[sizeof(T)] matches that of T which is a problem. We also do not round-trip a pointer to a valid T object because there wasn't a valid object of type T in our memory. And we don't know what compiler and options were used on the other side (maybe the struct on the other side is packed while ours is not).
In short, I see some potential problems with just casting raw char buffers into other types and would try to avoid writing code such as above. But apparently it works and is how "everybody does it".
My question is: is recovering structs sent over a network and received into a char buffer of appropriate size legal according to C++17 standard?
If not, what about using std::aligned_storage<sizeof(T), alignof(T)> to receive such structs? And if std::aligned_storage is not legal either, is there any legal way of sending raw structs over a network, or is it a bad idea that just happens to work... until it doesn't?
I view structs as a way of representing data types and treat the way the compiler lays them out in memory is an implementation detail and not as a wire format for data exchange to be relied upon, but I am open to being wrong.
[1] www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
The dicey part is not so much the memory alignment, but rather the lifetime of the T object. When you reinterpret_cast<> memory as a T pointer, that does not create an instance of the object, and using it as if it was would lead to Undefined Behavior.
In C++, all objects have to come into being and stop existing, thus defining their lifetime. That even applies to basic data types like int and float. The only exception to this is char.
In other words, what's legal is to copy the bytes from the buffer into an already existing object, like so:
char buffer[sizeof(T)];
// fill the buffer...
T value;
std::memcpy(&value, buffer, sizeof(T));
Don't worry about performance. The compiler will optimize all that away.

memory of a reference variable in c++?

I've just started to learn Cpp from the basics and am confused when I came across reference variables.
From what I have learn't reference variables are just like an alias (another name to the same memory), so in this case it need need any memory.
When I ran the below code:
class sample_class
{
public:
int num; //line1
int& refnum = num; //line2
}
int main()
{
sample_class sample_object;
cout<< "sample_class object size : " << sizeof(sample_object) <<endl;
return 0;
}
I got the output as:
sample_class object size : 8
==>Here, the size for num is 4 bytes (32-bit compiler) and refnum since a reference is simply an alias to num. Then, why in this case, the size of object is 8?
==>Also, if really an refnum is like an alias then when does this information (info that refnum also holds/alias to the same memory address of num) gets stored?
Edited :
And consider this case (changine the definition of sample_class):
class sample_class
{
public:
char letter; //line3
char& refletter = letter; //line4
char letter_two; //line5
}
Here, If I print the object size of sample_class object, I get it as 12 (though the size of letter,refletter and letter_two are each equal to 1). But if I comment line 4, the object size is just 2. How is this happening???
I'm interested to learn from the basics, so if I'm wrong anywhere please correct me
A reference is an alias, it should not be considered as a new variable. You cannot obtain its address and you cannot obtain its size. Any attempt to do so will instead obtain the address or size of the aliased object. In practice, most implementations implement them like pointers, but the standard does not require this. It makes no mention of the expected size for a reference.
From : http://en.cppreference.com/w/cpp/language/reference
References are not objects; they do not necessarily occupy storage, although the compiler may allocate storage if it is necessary to implement the desired semantics (e.g. a non-static data member of reference type usually increases the size of the class by the amount necessary to store a memory address).
Edit : The c++ standard gives a lot of leeway to implementations to decide for themselves the size of types and classes in order to accommodate the unique requirements of every architecture. In this case, padding is introduced between the members of your class. There is no requirement in c++ that a class's size must be equal to the sum of it's members' size. See Objects and alignment on cppreference.com for more information on the subject.
Edit 2 : There still seems to be some confusion regarding sizeof(T&).
From http://en.cppreference.com/w/cpp/language/sizeof :
When applied to a reference type, the result is the size of the referenced type.
The expression sizeof(T&) is treated as if you had written sizeof(T). This doesn't mean that the size of T& is equal to the size of T. It's simply that you cannot get the size of a reference directly with sizeof.
In addition to the answer already provided I would recommend having a read of the material regarding padding at:
Data structure padding
Which is a good basic discussion regarding padding of classes and structures in C++ with simple examples to consider.
A reference store the address of the variable it reference (like pointer with stronger pre/post-conditions).
This means that sizeof(T&) == sizeof(T*) == 4 on a 32bit architecture.
Comment from #FrançoisAndrieux about the real size of T&:
#nefas You state "This means that sizeof(T&) == sizeof(T*) == 4 on a 32bit architecture." but this is not true. Try it with a larger T. For example, sizeof(std::array<int, 10>&) is much larger than a pointer. You are taking the size of T, not T&.
An other thing that you have to take into account when calculating size of class/struct is the padding of the struct/class: the size of the struct maybe higher than the sum of the size of its member (I won't explain how the padding work because I haven't enough knowledge about it).

c++ pass array to function question

How is it possible to pass an array parameter to a function, and calculate the size of the array parameter? Because every time i try to calculate it, the return value is always 4.
Thanks the fast replies. I'm going to pass the size of the array as well then. Or i give a shot to vectors. Thanks
You can do it using templates as described here:
template<size_t Size>
void AcceptsArray( ParameterType( &Array )[Size] )
{
//use Size to find the number of elements
}
it is be called like this:
ParameterType array[100];
AcceptsArray( array ); //Size will be auto-deduced by compiler and become 100
The only drawback is that you now have a templated function and that increases code bloat. This can be addressed by redirecting the call to a non-templated function that accepts the address of the first element and the number of elements.
This is (one of) the difference between arrays and pointers. Taking the size of an array results in its size in bytes, whereas taking the size of a pointer yields the size of pointers on that system. However, whenever you pass an array to a function, it decays to a pointer, the size of which is always the same no matter what type of pointer it is (4 on a 32 bit machine).
So technically, it's impossible to pass an array into a function since whenever you try, it becomes a pointer.
You'll need to pass the size of the array in to the function as well, or better yet if you can, use std::vector or std::array, or std::string if you're using the array as a C-style string.
In C++ it is considered a bad pratice to use raw arrays. You should consider using std::vector or boost::array instead.
It is difficult to calculate the size of an array if you do not keep track of the size or supply some sort of an guardian value at the end. In C-strings (not std::strings), for example, the '\0' character marks the end of the string (a char array).
This works with g++:
template <typename T>
std::size_t size_of_array (T const & array)
{
return sizeof (array) / sizeof (*array);
}
int main ()
{
int x [4];
std::cout << "size: " << size_of_array (x) << '\n';
}
I guess it is because the function is inlined, but still it seems the array does not decay in this case. Can somebody explain why?
If you are using c arrays it's not possible because they're automatically casted to pointer when passing it to a function. So 4 is the size of the pointer.
Solution: use std::vector
#include <vector>
int carray[] = {1,2,3,4};
std::vector<int> v(carray, carray + sizeof(carray)/sizeof(int));
my_function(v);

Why does binary saving of array in a file works? [C++]

C++ newbie here.
I'm trying to figure out the following line that writes a buffer into a file:
fOut.write((char *)&_data, sizeof(_data));
_data = array of integers...
I have a couple of questions:
Is &_data the address to the first element of the array?
Whatever address it is, does that mean that we only save the address of the array? then how come I still can access the array after I free it?
Shouldn't I pass sizeof(_data)*arrLength? what is the meaning of passing the size of int (in this case) and not the size of the entire array?
What does casting into char* mean when dealing with addresses?
I would really appreciate some clarifications.
Contrary to your comment, the array must be automatic or static storage duration in order for sizeof to work.
It should be just (char*)_data. The name of an array implicitly converts to a pointer to the first element.
No, write expects a pointer, and stores the content found at that location, not the location's address.
No. Since _data is an array, sizeof (_data) is the cumulative size of all elements in the array. If _data were a pointer (such as when an array is dynamically allocated on the heap), you would want numElems * sizeof(_data[0]). Multiplying the size of a pointer by the number of elements isn't helpful.
It means that the content at that address will be treated as a series of individual bytes, losing whatever numeric meaning it might have had. This is often done to perform efficient bulk copy of data, either to and from a file, or with memcpy/memmove. The data type should be POD (plain old data) or you'll get unexpected results.
If _data is a pointer to an array allocated from the heap, as your comment suggests, then the code is badly broken. In that case, you are saving just the address, and it may appear to work if you load the file back into the same instance of your program, but that's just because it's finding the data still in memory at the same address. The data wouldn't actually be in the file, and if you re-started the program before loading the file, you'd find that the data was gone. Make the changes I mentioned in both (1) and (3) in order to save the complete array regardless of whether it's allocated automatic, static, or dynamically.
What does casting into char* means
when dealing with addresses?
Imagine this simple example
int x = 12;
char * z = (char *)&x;
And assume an architecture where int is 4 bytes long. From the C++ Standard sizeof(char)==1.
On the expression char * z the char * part, you could say that is being used for pointer arithmetic
on the Second line of the example I gave, what happens is that z now points to the first (out of 4 bytes) that x has. Doing a ++z; will make z point to the Second Byte of the (in my example) 4byte int
You could say that the left part of a declaration is used for pointer arithmetic, to simplify things. a ++(char *) would move you by one byte, while a ++(int *) would move you by the corresponding number of bytes int occupies on the memory.
Yes
No, write uses this address as the first location, and reads through sizeof(_data) writing the whole array
sizeof(_data) will return the size of the entire array not the same as sizeof(int)
Means the data will be read byte by byte, this is the pointer required by write as it writes in binary format(byte by byte)
1) Yes, &_data is the address of the first element of your array.
2) No, write() writes the number bytes you have specified via sizeof(_data) starting at address &_data
3) You would pass sizeof(int)*arrLength if _data is a pointer to an array, but since it is an array sizeof() returns the correct size.
4) don't know. ;)
read this : http://www.cplusplus.com/reference/iostream/ostream/write/
should be.
if you call "fstream.write(a,b)" then it writes b bytes starting from location a into the file (i.e. what the address is pointing at);
it should be the size in bytes or chars .
not much, similar to casting stuff to byte[] in more civilized languages.
By the way, it will only work on simple arrays with simple values inside them...
i suggest you look into the >> << operators .
is &_data the address to the first element of the array?
Yes, it is. This is the usual way to pass a "reference" to an array in C and C++. If you passed the array itself as a parameter, the whole array contents would be copied, which is usually wasteful and unnecessary. Correction: You can pass either &_data, or just _data. Either way, the array does not need to be copied to the stack.
whatever address it is, does that mean that we only save the address of the array? then how come I still can access the array after I delete him from the memory?
No, the method uses the address it gets to read the array contents; just saving the memory address would be pointless, as you point out.
Shouldn't I pass sizeof(_data)*arrLength? I mean...
what is the logic of passing the size
of int (in this case) and not the size
of the entire array?
No, sizeof(_data) is the size of the array, not of one member. No need to multiply by length.
What does casting into char* means when dealing with addresses?
Casting to char* means that the array is accessed as a list of bytes; that's necessary for accessing and writing the raw values.