struct student
{
int roll_no;
int physics;
int chem;
float percentage;
};
int main()
{
struct student s = {1, 96, 98, 97.00};
printf("%d", *((int *) &s 1));
}
Here in the above code we know that 's' is a structure variable and what my question is
whether 's' is a decay pointer or a separate stack frame is getting allocated for the structure, if it is a decay pointer we don't have to put that '&' with the 's' so i'm guessing it must be a stackframe cause it behaves just like a normal variable.
if we print 's' first members value gets printed and if we print '&s' first members address gets printed.
If it is anything other than this kindly help us to understand that too.
And also,
How to access if a Char array is a member of the structure, tried this *((char*)&s offset_value);
not working.
Your help will be much appreciated.
CodePudding user response:
whether 's' is a decay pointer…
s
is a structure. Structures are not automatically converted to pointers the way arrays are. (Some people say “decay,” but this is a colloquial term and is inaccurate.)
… or a separate stack frame is getting allocated for the structure,…
With s
defined as you show inside main
, the compiler automatically allocates space for it. In common C implementations, the compiler uses stack space for this (except that optimization may result in alternatives including using processor registers instead, incorporating use of the structure into other expressions, or eliminating part or all of the structure entirely). If the compiler does use stack space for s
, it uses space within the stack frame for main
; it does not allocate a separate stack frame.
(Generally, a stack frame is the space on the stack used by one function, sometimes with some modifications such as “leaf” functions that do not call other routines and may not establish a full stack frame.)
printf("%d", *((int *) &s 1));
*((int *) &s 1)
is not proper C code because its behavior is not defined by the C standard and likely not by your compiler either.
&s
is the address of the structure s
. When we convert it to (int *)
, that gives the address of the first member of the structure, s.roll_no
. That is because the C standard gives us a rule that says we can convert a pointer to a structure to a pointer to its first member. C 2018 6.7.2.1 15 says:
… A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa…
Then you add 1 to this pointer, (int *) &s 1
. That also has defined behavior. From above (int *) &s
points to s.roll_no
, so it is equivalent to &s.roll_no
. Then (int *) &s 1
is equivalent to &s.roll_no 1
. C 2018 6.5.6 specifies what happens with addition. I will omit specifics of the rules, but essentially &s.roll_no 1
is defined and produces a pointer that points just beyond s.roll_no
.
However, even if the next member of the structure, physics
, is just beyond s.roll_no
1, the C standard does not define what happens when *
is applied to it. This is because C 2018 6.5.6 8 says:
If the result [of the addition] points one past the last element of the array object, it shall not be used as the operand of a unary
*
operator that is evaluated.
In the context of 6.5.6, s.roll_no
is an “array object” that contains just one element, and &s.roll_no 1
points one beyond its last element. So *(&s.roll_no 1)
and, equivalently, *((int *) &s 1)
violates this rule. C 2018 4 2 says that when a rule like this is violated, the behavior is not defined:
If a "shall" or "shall not" requirement that appears outside of a constraint or runtime-constraint is violated, the behavior is undefined…
Footnote
1 This is not guaranteed because C implementations are allowed to insert padding between members in structures. However, typical C implementations will not insert padding between members of identical types, as it is not needed for alignment, and this can be checked at compile time. But the statements above apply even if there is no padding.
CodePudding user response:
Structs parameters are passed by value unless the &
operator is used. Arrays parameters are passed as pointers. A local variable is in the stack frame (or a register).
You might find the offsetof
macro interesting
#define offsetof(S, F) (((char *)&((S *)0)->F - (char *)0))