What are the rules for structure alignment of nested structures? - visual-c++

I'm trying to understand the rules for alignment of nested structures, specifically on Win32/MSVC. I have this structure:
struct outer {
int a;
struct {
int aa;
int bb;
} inner;
int d;
};
The inner structure has a size of 8 bytes; its two int fields pack nicely. Within the outer struct, the inner structure is located after a, which is 4 bytes. The inner structure has a size of 8. When I compile this code, it ends up having offset 4, which implies that the inner structure has an alignment requirement of 4.
I thought the size of inner (8) would be used as its alignment "granularity", but I'm clearly wrong. What is the rule that I should be applying to calculate these offsets?

Related

What is the difference between these two types of data struct?

Can anyone tell me what the difference between these two types of data structures is? The first one uses TAG "worker". In the second one I declared the names in the data structure itself "rober" and "zzymon". As for me, the first one is more practical to use...
// FIRST structure TAG**
struct worker
{
int age1;
char *hair_color1;
};
struct worker grzegorz;
grzegorz.age1 = 15;
grzegorz.hair_color1 = "gray";
struct worker krzys;
krzys.age1 = 26;
krzys.hair_color1 = "white";
// SECOND structure variables struct type**
struct
{
int age2;
char *hair_color2;
}
robert, szymon;
robert.age2 = 12;
robert.hair_color2 = "blond";
szymon.age2 = 14;
szymon.hair_color2 = "gray";
The first one defines a struct type struct worker and then later defines two instances of that struct type grzgorz and krzys.
The second one defines two instances of an anonymous struct type called robert and szymon
In both cases, you get two objects of the same struct type you can do things with. In the first case, that struct type also has a name, so you can later define other things with the same type (or pointers to that type, etc), while in the second case you cannot, as the struct type is anonymous.

wgpu-rs: Putting a Matrix3 into a vertex shader results in odd behavior but using a Matrix4 works fine

Using wgpu-rs, I'm trying to get a 3x3 cgmath matrix into a shader (compiled using glsl-to-spirv). However, the resulting mat3 in the shader has incorrect data. When I replace the mat3 and Matrix3 with mat4 and Matrix4, everything works fine and the matrix has correct data.
Vertex Shader:
layout(set=0, binding=0) uniform Uniforms {
mat3 camera_transform;
};
Render Loop:
let mut encoder = self.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor {
label: Some("update encoder"),
},
);
let staging_buffer = self.device.create_buffer_with_data(
bytemuck::cast_slice(&[self.uniforms]),
wgpu::BufferUsage::COPY_SRC,
);
encoder.copy_buffer_to_buffer(&staging_buffer, 0, &self.uniform_buffer, 0, std::mem::size_of::<Uniforms>() as wgpu::BufferAddress);
self.queue.submit(&[encoder.finish()]);
// ...
render_pass.set_bind_group(0, &self.uniform_bind_group, &[]);
Uniforms:
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Uniforms {
pub camera_transform: Matrix3::<f32>,
}
unsafe impl bytemuck::Pod for Uniforms {}
unsafe impl bytemuck::Zeroable for Uniforms {}
impl Uniforms {
pub fn new() -> Self {
Self {
camera_transform: Matrix3::identity(),
}
}
}
This is an open issue in wgpu-rs. Indeed the simplest workaround may be to make your mat3 into a mat4 until it is resolved.
The problem seems to be a mistake of alignment in generating SPIR-V. The actual alignment is:
If the member is a scalar consuming N basic machine units, the base alignment is N.
If the member is a two- or four-component vector with components consuming N basic machine units, the base alignment is 2N or 4N,
respectively.
If the member is a three-component vector with components consuming N basic machine units, the base alignment is 4N.
If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array
element, according to rules (1), (2), and (3), and rounded up to the
base alignment of a vec4. The array may have padding at the end; the
base offset of the member following the array is rounded up to the
next multiple of the base alignment.
You are in case 4. Having a mat4 should leave no extra padding on the end and not give any possibility for misalignment issues.

How to pass a SystemVerilog struct containing a dynamic array via DPI-C?

Here is a minimal working example of the problem:
Below example compiles fine (using Cadence Incisive/Xcelium) if I comment out the import "DPI-C" statement and the call to print_object(s);.
So that proves that the struct with dynamic array is a legal SystemVerilog syntax.
But if I try to pass the same struct via DPI-C, I get the error:
xmvlog: *E,UNUSAG (tb.sv,10|62): unsupported element in unpacked struct datatype in formal argument.
program top;
typedef struct {
int scalar_int;
int dyn_arr_int[];
} my_struct_s;
import "DPI-C" function void print_object(input my_struct_s s);
// Cannot pass a dynamic-array containing struct via DPI-C.
// import "DPI-C" function void print_object(input my_struct_s s);
// |
// xmvlog: *E,UNUSAG (tb.sv,10|62): unsupported element in unpacked struct datatype in formal argument.
initial begin
my_struct_s s;
s.scalar_int = 100;
s.dyn_arr_int = '{25, 35, 45};
$display("Value of the struct printed from SV: %p", s);
print_object(s);
$finish;
end
endprogram : top
So the question is:
Is there a workaround to pass structs with dynamic arrays to the C side? Is there a way to pass structs with "pointers" to those dynamic arrays? Or any other way?
One workaround is to pass a struct with a static array of some "max" size and also pass a scalar integer storing the length of actual data that's a subset of that static array. But that's a very ugly workaround, requires overhead in SystemVerilog to calculate the lengths and to populate that static array, and is also probably inefficient compared to passing just the dynamic array.

What value will contain_of() return when two different integers are considered in a structure

Consider we defined a structure T
struct T {
int a, b;
};
if the address of b is 0x8b3000c and sizeof(int) is 4. what value will container_of() return when invoked
container_of is a macro in linux kernel code, which calculates address of container.
For ewxample, in your case
struct T {
int a, b;
};
Applying container_of on address of b will yield address of struct T
struct T *pT = container_of(ptr_b, struct T, b);
where ptr_b will hold the address of b, &b
Normally, we won't care the physical value we got, like 0x8b3000c, as we work with identifiers.
As you are interested in physical, as both members are int with size 4, ignoring padding, pT will have (Ox8b3000c -4) = Ox8b30008
BUT BUT, Please never make such assumption while coding, struct may be padded. It is always good to use sizeof

I don't understand this nested struct

The struct is:
struct
{
int x;
struct
{
int y, z;
} nested;
}
i={.nested.y = 5, 6, .x = 1, 2};
Question: The result is i.nested.y = 2; i.nested.z = 6;
I cannot get or understand this, the inner one is also a struct but union, so could anyone help me?
Ok, first of all let me say that this is a terrible way to initialize a struct, and if it's a homework question - it's not a very good one either.
However, given the problem at hand, what I believe is happening in the initialization is this: first, y is initialized to 5, and z, being the next member in the struct, is initialized to 6. Then, x is initialized to 1 and the next member in the struct, in this case y, is initialized to 2 (which overwrites the 5).
Something important to note as well, is that the nested struct isn't a union, but a struct - first of all, because that's what the code says, but also because if it were a union - it would be impossible in this case for y and z to have different values, since both would be kept in the same location in the memory.

Resources