how to copy to array inside struct? - c++

How to copy to flexible array inside struct in c?
#include <stdio.h>
#include <string.h>
typedef struct
{
int val;
char buf[];
} foo;
int main()
{
foo f;
f.val = 4;
// f.buf = "asd"; -> invalid use of flexible array member
memcpy(f.buf, "asd\0", 4);
printf("%s\n", f.buf);
}
output:
asd
*** stack smashing detected ***: terminated
Aborted (core dumped)
Also, if the struct was declared as:
typedef struct
{
char buf[];
} foo
vscode editor gives error:
incomplete type is not allow
and gcc gives error:
error: flexible array member in a struct with no named members
6 | char buf[];
Why is array in struct now allowed but pointer is? (char *buf).
Also, If a struct has a flexible array, what is its sizeof(struct containsFlexArray)? How can I dynamically resolve its array, when it has no dimension?
EDIT:
if the above works in C++, because the incomplete array "decay" to pointer of known length (8 bytes in x64), why is this not also the case in c? If I peek to asm, I see the program does not allocate enough stack for the struct (it allocates only space for foo.val member, but not bur foo.buf member, in which case the program tries to use override the foo.val member (by using its address instead of foo.buf), which causes the stack smashing detected. But why is it implemented this wrong way? (So I want to know the rationale behind introducing flexible array as well)

You may want to read information on flexible array member here.
It seems as, when using a flexible array in a struct there must be at least one other data member and the flexible array member must be last.
And also you may have an element of clarification concerning the usage of flexible array members in C here

lets use intel/amd architecture here where char => 1 byte int => 4 and long is 8 bytes long.
Struct alignment is an issue here. You see when you declare a struct in c, compiler looks at it as individual block. So if you have a struct like this:
struct a {
long l;
char c1;
char c2;
}
compiler looks at the first type used, and allocates 8 bytes of memory for l, looks at c and determines that c1 is shorter than l and rather than figure out what c1's type is, it allocates 8 bytes of data for c1. It does the same for c2. So you end up with struct that is 24 bytes long and only 10 are used. Where if you use this:
struct b {
char c1;
long l;
char c2;
}
this will allocate 1 byte for c1, 8 byte for l, and 8 bytes for c2. So you end up with 17 bytes and 10 used. Where as if you have this:
struct b {
char c1;
char c2;
long l;
}
well it allocates 1 byte for c1, 1 byte for c2, and 8 bytes for l. In total 10 bytes but all 10 are used.
So what does it have to do with array? You see if you have:
struct aa {
char a;
long b[];
}
This will know to allocate at least one byte for b initially. Where when you do not have char a,
struct aa {
long b[];
}
Compiler might not allocate any memory (allocate 0 bytes), because it simply does not know how much to allocate.
EDIT:
Left my PC and in mean time other answer popped up. The other answer is very good!!! But I hope this helps you understand what is going on.

You did not initialize the buf[] array when you declared an instance in main(). The compiler does not know how much memory to allocate. The stack smashing is a compiler feature that keeps your program from doing... bad things to you computer. Add a number to your array declaration in typedef struct.
Like this:
` #include <stdio.h>
#include <string.h>
typedef struct
{
int val;
char buf[5];
} foo;
int main()
{
foo f;
f.val = 4;
// f.buf = "asd"; -> invalid use of flexible array member
memcpy(f.buf, "asd\0", 4);
printf("%s\n", f.buf);
}`

Related

How do I 'fill up' remainder of a size at compile time?

Let's say I have the following
struct MyType { long a, b, c; char buffer[remainder] }
I wanted to do something like
char buffer[4096 - offsetof(MyType, buffer)]
But it appears that it's illegal
You can do:
struct ABC {long a,b,c; }
struct MyType : ABC {char buffer[4096-sizeof(ABC)];};
static_assert(sizeof(MyType)==4096,"!");
Your problem stems from trying to use the not-yet-fully-defined MyType type while defining it. You could do this with a union:
#include <iostream>
struct MyType {
union {
struct { long a, b, c; } data;
char buffer[4096];
};
};
static_assert(sizeof(MyType) == 4096, "MyType size should be exactly 4K");
int main() {
MyType x;
x.data.a = 42;
std::cout << sizeof(x) << " " << x.data.a << "\n";
return 0;
}
The output (on my system):
4096 42
Because it's a union, the type actually holds the a/b/c tuple and buffer area in an overlapped region of memory, big enough to hold the larger of the two. So, unless your long variable are really wide, that will be the 4K buffer area :-)
In any case, that size requirement is checked by the static_assert.
That may be less than ideal as buffer takes up the entire 4K. If instead you want to ensure that buffer is only the rest of the structure (after the long variables), you can use the following:
struct MyType {
long a, b, c;
char buffer[4096 - 3 * sizeof(long)];
};
and ensure that you use x.something rather than x.data.something when accessing the a, b, or c variables.
This solves your problem by using the size of three longs (these are fully defined) instead of the size of something not yet defined. It's still a good idea to keep the static_assert to ensure overall size is what you wanted.
Technically, the compiler has total control over padding and layout. A union/struct combo combined with a static_assert sanity check might be enough for government work, but std::aligned_storage is also there to give you memory blocks that are safe to put objects in.
struct MyType {
long a, b, c;
};
using MyTypeStorage = std::aligned_storage<4096, std::alignment_of<MyType>::value>::type;
/* ... */
MyTypeStorage myTypeStorage;
MyType* x = new (&myTypeStorage) MyType {};
https://godbolt.org/z/87e7Tc

Struct sizes and address of struct members [duplicate]

This question already has answers here:
Weird Pointer Address for Individual Struct Data Member
(2 answers)
Closed 8 years ago.
2 questions about the below code:
1 Why is the size of struct b 12 bytes (line 2 of output)? I can understand why a is 12 bytes (to align k on the 4 byte boundary), however shouldnt b be 9 bytes and not 12?
2 Why is using the & operator to get the address of the char members not displaying a valid address? (middle output in the last 2 lines)
#include<iostream>
using namespace std;
struct a
{
int i;
char j;
int k;
};
struct b
{
int i;
int k;
char j;
};
int main()
{
a s1;
b s2;
cout<<sizeof(a)<<endl;
cout<<sizeof(b)<<endl;
cout<<sizeof(int)<<endl;
cout<<sizeof(char)<<endl;
cout<<&s1.i<<'\t'<<&s1.j<<'\t'<<&s1.k<<endl;
cout<<&s2.i<<'\t'<<&s2.j<<'\t'<<&s2.k<<endl;
}
Output:
12
12
4
1
0x28ff14 - 0x28ff1c
0x28ff08 4A 0x28ff0c
If b were 9 bytes large and you had an array
b foo[2];
then foo[1].i would not be aligned to four-byte boundaries.
As for the char members, their address is of type char *, and std::ostream has an operator<< for those that interprets them as a C-style string. If you want to see their address, static_cast<void*>(&s1.j) is your friend.
EDIT: Full disclosure of egg on my face: This originally stated that some compilers defined minimum struct alignment sizes; upon investigation, this turns out to be untrue. Well, it could be true, since the size of struct types is not specified in the standard to that extent, but common compilers don't appear to do it. Sorry about that.
Why is the size of struct b 12 bytes (line 2 of output)?
It has int fields, and so has the same alignment requirement as int - four bytes, in your case. Three padding bytes are added at the end, so the size is a multiple of four, to give the required alignment.
This applies even at the end of the structure, so that the next element of an array is properly aligned.
Why is using the & operator to get the address of the char members not displaying a valid address?
Because << interprets a pointer to a character type as a pointer to a C-style string, and prints memory contents until it finds a zero value. To print the address, cast to a non-character pointer type:
cout << (void*)&j;

how to write 8 bytes to a void * address?

So I have a defined a 8 bytes data structure
typedef struct __attribute__((__packed__)) entry{
// something here total 64 bits;
}entry_t;
and I have a void* basewhich is a pointer pointing to the base of where I want to put the entry.
Will
entry_t a;
*base = a;
do the job?
or I have to cast base to pointer to entry_t?
UPDATE
Sorry I didn't mention I can't use memcpy, because the kernel I am using doesn't implement memcpy yet.
Either:
*((entry_t *)base) = a;
or
memcpy(base, &a, sizeof a);
Of course, make sure that there are in fact 8 bytes there to copy into.
Convert the pointer to unsigned char * and write the 8 bytes with 8 uses of the assignment operator (either in a loop, or unrolled).

How is memory allocated for stack variables?

On VS (release), I run the following:
int main(void)
{
char b[] = "123";
char a[] = "1234567";
printf("%x %x\n", b,a);
return 0;
}
I can see that, the mem address of a is b+3(the length of the string). Which shows that the memory are allocated with no gaps. And this guarantee that least memories are used.
So, I now kind of believe that all compilers will do so.
I want to make sure of this guess here. Can somebody give me an more formal proof or tell me that my guess is rooted on a coincidence.
No, it's not guaranteed that there will always be perfect packing of data.
For example, I compiled and runned this code on g++, and the difference is 8.
You can read more about this here.
tl;dr: Compilers can align objects in memory to only addresses divisible by some constant (always machine-word length) to help processor(for them it's easier to work with such addresses)
UPD: one interesting example about alignment:
#include <iostream>
using namespace std;
struct A
{
int a;
char b;
int c;
char d;
};
struct B
{
int a;
int c;
char b;
char d;
};
int main()
{
cout << sizeof(A) << " " << sizeof(B) << "\n";
}
For me, it prints
16 12
There is no guarantee what addresses will be chosen for each variable. Different processors may have different requirements or preferences for alignment of variables for instance.
Also, I hope there were at least 4 bytes between the addresses in your example. "123" requires 4 bytes - the extra byte being for the null terminator.
Try reversing the order of declaring a[] and b[], and/or increase the length of b.
You are making a very big assumption about how storage is allocated. Depending on your compiler the string literals might get stored in a literal pool that is NOT on the stack. Yet a[] and b[] do occupy elements on the stack. So, another test would be to add int c and compare those addresses.

Struct to string and vice versa

I would like to take the memory generated from my struct and push it into a byte array (char array) as well as the other way around (push the byte array back into a struct). It would be even better if I could skip the string generation step and go directly to writing memory into the EEPROM. (Do not worry about the eeprom bit, I can handle that by reading & writing individual bytes)
// These are just example structs (I will be using B)
typedef struct {int a,b,c;} A;
typedef struct {A q,w,e;} B;
#define OFFSET 0 // For now
void write(B input)
{
for (int i=0;i<sizeof(B);i++)
{
eepromWrite(i+OFFSET,memof(input,i));
}
}
B read()
{
B temp;
for (int i=0;i<sizeof(B);i++)
{
setmemof(temp,i,eepromRead(i+OFFSET));
}
return temp;
}
This example I wrote is not supposed to compile, it was meant to explain my ideas in a platform independent environment.
PLEASE NOTE: memof and setmemof do not exist. This is what I am asking for though my question. An alternative answer would be to use a char array as an intermediate step.
Assuming your structures contain objects and not pointers, you can do this with a simple cast:
save_b(B b) {
unsigned char b_data[sizeof(B)];
memcpy(b_data, (unsigned char *) &b, sizeof(B));
save_bytes(b_data, sizeof(B));
}
Actually, you shouldn't need to copy from the structure into a char array. I was just hoping to make the idea clear.
Be sure to look into #pragma pack, with determines how the elements in the stuctures are aligned. Any alignment greater than one byte may increase the size unnecessarily.