Accessing struct element straight from function call in C - c

I don't fully understand if it's normal to get struct element straight from function call which returns struct (or pointer to struct) like in the following lines of code:
function().num
ptr_function(&var)->num
Below is code example I wrote which compiles and runs without any issues on my system.
#include <string.h>
#include <stdio.h>
#define LEN 32
typedef struct
{
int num;
char str[LEN];
} myType;
myType function( void )
{
myType var;
var.num = 10;
strncpy( var.str, "Hello!", LEN );
return var;
}
myType* ptr_function( myType* var )
{
var->num = 20;
strncpy( var->str, "Hello ptr!", LEN );
return var;
}
int main()
{
/* 1st example */
printf( "%d %s\n", function().num, function().str );
/* 2nd example */
myType var;
printf( "%d %s\n", ptr_function(&var)->num, ptr_function(&var)->str );
return 0;
}
And it returns the following:
10 Hello!
20 Hello ptr!
So my question is: Are there any issues or undefined behaviour which will arise from doing the following in c99 or c11?
function().num
ptr_function(&var)->num

Your example is technically correct and safe.
Do note that function() or ptr_function(&var) gets called twice. For some functions, that might not be desirable! And if you had different function calls such as outer(function1().value, function2().value), the order of the two function calls is not specified, so that could cause nasty surprises if they have interacting side effects.
Another possible catch to the pointer version of the pattern: If a function returns a pointer to allocated memory and expects the caller to free it, immediately using the return value result means the caller isn't keeping that pointer value and can't actually free it later.
[For a case like that, the code could still do:
someType *ptr;
outer_func((ptr = allocating_func())->field);
// ...
free(ptr);
but this is getting pretty strange and difficult to read. And since you need to declare ptr anyway, why not initialize it on the same line?]
This isn't an issue with the given example since the pointer actually points at var in main, so it doesn't need to be freed and is still valid when the -> operator is evaluated.

Related

stack question: a pointer points to a variable inside function(stack)

a variable defined in a function is created on stack. then, when function call completed, the variable is vanished due to stack in/out.
the following code is passing a data structure
typedef struct
{
test_out_t output;
test_in_t input;
} message_t;
typedef struct
{
uint8_t len;
uint8_t* data_out;
} test_out_t;
typedef struct
{
uint8_t len;
uint8_t* data_in;
} test_in_t;
The function call is
void test(message_t *msg);
in the function, I defined a array, and assigned the pointer points to this array(the memory location). However, when the function call completed, I am expecting the pointer points the value becomes undetermined/Zeros, since the stack variable is gone.
However, it still has the value of the stack variable if I call printf() inside the function.
with the following code, the msg.output.data_out contains the value of array which created in the function.
If comment out the printf inside the test(). the msg.output.data_out is all zeros.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define DATA_SIZE (8)
typedef struct
{
uint8_t len;
uint8_t* data_out;
} test_out_t;
typedef struct
{
uint8_t len;
uint8_t* data_in;
} test_in_t;
typedef struct
{
test_out_t output;
test_in_t input;
} message_t;
void test(message_t *msg);
void test(message_t *msg)
{
uint8_t stackdata[DATA_SIZE];
memset(stackdata, 0, DATA_SIZE);
for (int i=0; i<DATA_SIZE; i++)
stackdata[i] = i+1;
msg->output.len = DATA_SIZE;
msg->output.data_out = stackdata;
uint8_t data2[msg->input.len];
memcpy(&data2, msg->input.data_in, msg->input.len);
for (int i=0; i<msg->input.len; i++)
printf("0x%X\t", data2[i]);
}
int main(void) {
message_t msg;
uint32_t data2 = 0x12345678;
msg.input.len = 4;
msg.input.data_in = (uint8_t*)&data2;
test(&msg);
printf("\n");
for (int i=0; i<msg.output.len; i++)
printf("0x%X\t", msg.output.data_out[i]);
return 0;
}
I assume something related to printf()
BTW, I am using online compiler to run the code.
https://repl.it/languages/c
The rules of C say that, when the lifetime of an object ends1, no guarantee is made to you about it. Thus, you cannot properly use it because you have no guarantee about it. The rules do not say that anything erases or randomizes the object.
In typical implementations, when a function returns, the stack pointer is changed to point to the new top of stack. Nothing does any extra work to erase any data on the stack. So it is still there until something else happens.
That does not mean you can reliably use the space on the stack. A variety of things can alter the data or alter your use of it:
Other routine calls will use the stack.
Other operations in the current routine may use the stack.
Signals could cause the stack to be used.
If the compiler observes your unsupported use of the object, its optimization might transform your program in unexpected ways.
Footnote
1 “The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it” (C 2018 6.2.4 1). For regular objects defined in functions, their lifetimes end when execution of the function ends (usually because the function returned, but possibly because a longjmp was executed or the program is being terminated). So, when the lifetime ends, all it means is that the storage is no longer guaranteed to be reserved. The storage still exists. Nothing is guaranteed to change it. All that changes is that while the function is executing, you are guaranteed the storage is reserved for that object, and, after the function ends, the guarantee is gone.

SIGSEGV (Segmentation fault) when passing a structure to callback in C

I got some strange behavior of my code.
I can`t pass a structure to the callback function.
#include <malloc.h>
#include "stdint.h"
typedef struct {
int test_rssi;
int setup_rssi;
} test_setup_scan_result;
typedef void (*WifiCallback)(uint8_t);
WifiCallback TestSetupCb;
void resume_configuration(test_setup_scan_result *result) {
if (result == NULL) {
printf("result is NULL\n");
return;
}
printf("result is not NULL\n");
printf("setup_rssi %d\n", result->setup_rssi);
printf("test_rssi %d\n", result->test_rssi);
printf("done");
}
void scan_test_setup_done_cb() {
printf("scan_done\n");
test_setup_scan_result *scan_result = malloc(sizeof(test_setup_scan_result));
printf("created structure\n");
scan_result->test_rssi = 1;
scan_result->setup_rssi = 1;
printf("filled structure\n");
if (TestSetupCb) {
printf("executing cb\n");
printf("setup_rssi %d\n", scan_result->setup_rssi);
printf("test_rssi %d\n", scan_result->test_rssi);
TestSetupCb((uint8_t) scan_result);
}
}
void scan_for_test_setup(WifiCallback cb) {
TestSetupCb = cb;
scan_test_setup_done_cb();
}
int main(void) {
printf("Hello World\n");
scan_for_test_setup((WifiCallback)resume_configuration);
return 0;
}
The code after I am trying to get values of the structure in resume_configuration function just not works. I am the newbie in c language so any links to useful articles are regarded.
Casting a function name to a function pointer type with incompatible parameter types is undefined behavior:
scan_for_test_setup((WifiCallback)resume_configuration);
// ^^^^^^^^^^^^^^
// Undefined behavior
This by itself is enough to get a crash. However, your program does another thing illegally - the call below
TestSetupCb((uint8_t) scan_result);
// ^^^^^^^^^^^
// Does not fit in uint8_t
would fail regardless of the function pointer cast, because a pointer does not fit in 8 bits.
The variable “scan_result” is pointer to struct with allocated memory space in heap region.
When the TestSetupCb() is called with argument “(uint8_t) scan_result” you actually casting address of “scan_result” to be uint8_t, which means to take a first byte of the address and pass it by value. In that case you lose data that you want process in resume_configuration() function.
For example: let’s say the “scan_result” struct it at address “0x004EE388” when you casting this address to uint8_t the result is “0x00000088” this address is invalid and creates issue in your program. Also, this kind of operation creates dangerous to your program.
To solve your problem just re-define function pointer in the following way:
typedef void(*WifiCallback)( test_setup_scan_result *);
and update your code: instead of TestSetupCb((uint8_t)scan_result); change to TestSetupCb(scan_result);
I have run it in Valgrind and I have identified a blatant error (which manifests in several places):
resume_configuration does not obey the WifiCallback pointer type; it takes a parameter of pointer type, not of uint8_t type which most likely has a different size (and it indeed has)
You call TestSetupCb((uint8_t) scan_result); -- you explicitly convert the scan_result pointer to a datatype smaller than a pointer. You have truncated a pointer, so now the result cannot be converted back into a valid pointer. The truncation on Intel systems is so bad, any resulting pointer will always be in the NULL page.

Pointer to a local variable survives

I'd like to ask a simple question. Please, consider the attached code. In the main function, a pointer to a struct is built in two different ways by means of either ctor1 or ctor 2. In both cases the program works no matter which constructor I use.
The reason why ctor1 works is that memory for struct instance is allocated outside the function frame (i.e. in the heap). Therefore, it will be available in the main function after ctor1 termination.
My question boils down to ctor2 function. As far as I know, the local variable "myPtr foo" is expected to be destroyed at the function end. Hence, "that" pointer should point to nothing from now on. Having executed the program however, I found out that both constructors work flawlessly.
Obviously, there is a subtle detail that eludes me. Could you explain why function ctor2 works?
Thank you in advance!
#include <stdio.h>
#include <malloc.h>
int _method(void) {
return 0;
}//_foo
typedef struct vTable {
int (*method)(void);
} myPtr;
myPtr *ctor1(void) {
myPtr *foo;
foo = (myPtr*)malloc(1 * sizeof(myPtr));
foo->method = &_method;
return foo;
}//ctor1
void ctor2(myPtr *that) {
myPtr foo = { &_method };
that = &foo;
return;
// having reached the function end "foo" is destroyed
// and "that" should point to nothing, supposedly
}//ctor2
int dtor(myPtr *foo) {
free(foo);
foo->method = NULL;
foo = NULL;
return 0;
}//dtor
int main(void) {
myPtr *vPtr;
// it works as expected
vPtr = ctor1();
printf("%p\n\n", vPtr); // 003E0F68
dtor(vPtr);
// it works surprisingly enough
ctor2(vPtr);
printf("%p\n", vPtr); // 003E0F68
printf("%p\n", vPtr); // 003E0F68
// it keeps on working
printf("%p\n", vPtr); // 003E0F68
dtor(vPtr);
return 0;
}//main
Screenshot
The code void ctor2(myPtr *that) declares that to be a parameter that points to an object of type myPtr. Parameters are passed by value, so the parameter that is only a copy of whatever was passed. Changing that does not change the thing that was passed.
If you want to change the value of a pointer to myPtr, you must pass a pointer to a pointer to myPtr:
void ctor2(myPtr **that)
Then you can change it with:
*that = malloc(…);
There are several problems here, let's go through them one by one.
First, in your ctor2 function:
void ctor2(myPtr *that) {
myPtr foo = { &_method };
that = &foo;
return;
}//ctor2
This function is actually taking in a pointer to myPtr by value and modifying it locally to point to something allocated on the stack in the function. This has on effect on the pointer passed in. If you wanted to modify the pointer passed in, you would have passed in a double pointer and dereference it:
void ctor2(myPtr **that) {
//malloc foo
*that = foo;
return;
}
Secondly, because you never modified vPtr through the call to ctor2 the second call to dtor is freeing already freed memory, which is undefined behavior that usually leads to a crash. I'm surprised it didn't crash on your system, but that's the thing with UB, you never know.
Thirdly, the behavior you wanted to emulate is:
/* constructor */
void Shape_ctor(Shape * const me, int16_t x, int16_t y) {
static struct ShapeVtbl const vtbl = { /* vtbl of the Shape class */
&Shape_area_,
&Shape_draw_
};
me->vptr = &vtbl; /* "hook" the vptr to the vtbl */
me->x = x;
me->y = y;
}
The difference is that in this case the ShapeVtbl structure is statically allocated. This is OK because it only points to functions, which will not change from object instance to object instance. But having it statically allocated allows it to be allocated within a function like that and assigned to the object.
To amplify Eric Postpischil's excellent answer, consider,
void foo( int i ) { i++; }
This function changes the value it was passed, but not that value is a copy of the original when it was invoked,
int j=8;
foo(j);
You wouldn't expect j to change, right?
The same is true for
void ctor2(myPtr *that) { // my version
that = NULL;
}
that is a copy of the parameter passed on invocation,
ctor2(vPtr);
Because vPtr doesn't change, your program prints ... its unchanged value.
ctor2 can change the value of anything pointed to by that, but any change to the parameter itself has only a local effect.
There are other errors in your program, as other answers point out. But the answer to why ctor2 "works" is basically that it doesn't do anything.

C Function implementation - with Pointer vs without Pointer

I've just started to work with C, and never had to deal with pointers in previous languages I used, so I was wondering what method is better if just modifying a string.
pointerstring vs normal.
Also if you want to provide more information about when to use pointers that would be great. I was shocked when I found out that the function "normal" would even modify the string passed, and update in the main function without a return value.
#include <stdio.h>
void pointerstring(char *s);
void normal(char s[]);
int main() {
char string[20];
pointerstring(string);
printf("\nPointer: %s\n",string);
normal(string);
printf("Normal: %s\n",string);
}
void pointerstring(char *s) {
sprintf(s,"Hello");
}
void normal(char s[]) {
sprintf(s,"World");
}
Output:
Pointer: Hello
Normal: World
In a function declaration, char [] and char * are equivalent. Function parameters with outer-level array type are transformed to the equivalent pointer type; this affects calling code and the function body itself.
Because of this, it's better to use the char * syntax as otherwise you could be confused and attempt e.g. to take the sizeof of an outer-level fixed-length array type parameter:
void foo(char s[10]) {
printf("%z\n", sizeof(s)); // prints 4 (or 8), not 10
}
When you pass a parameter declared as a pointer to a function (and the pointer parameter is not declared const), you are explicitly giving the function permission to modify the object or array the pointer points to.
One of the problems in C is that arrays are second-class citizens. In almost all useful circumstances, among them when passing them to a function, arrays decay to pointers (thereby losing their size information).
Therefore, it makes no difference whether you take an array as T* arg or T arg[] — the latter is a mere synonym for the former. Both are pointers to the first character of the string variable defined in main(), so both have access to the original data and can modify it.
Note: C always passes arguments per copy. This is also true in this case. However, when you pass a pointer (or an array decaying to a pointer), what is copied is the address, so that the object referred to is accessible through two different copies of its address.
With pointer Vs Without pointer
1) We can directly pass a local variable reference(address) to the new function to process and update the values, instead of sending the values to the function and returning the values from the function.
With pointers
...
int a = 10;
func(&a);
...
void func(int *x);
{
//do something with the value *x(10)
*x = 5;
}
Without pointers
...
int a = 10;
a = func(a);
...
int func(int x);
{
//do something with the value x(10)
x = 5;
return x;
}
2) Global or static variable has life time scope and local variable has scope only to a function. If we want to create a user defined scope variable means pointer is requried. That means if we want to create a variable which should have scope in some n number of functions means, create a dynamic memory for that variable in first function and pass it to all the function, finally free the memory in nth function.
3) If we want to keep member function also in sturucture along with member variables then we can go for function pointers.
struct data;
struct data
{
int no1, no2, ans;
void (*pfAdd)(struct data*);
void (*pfSub)(struct data*);
void (*pfMul)(struct data*);
void (*pfDiv)(struct data*);
};
void add(struct data* x)
{
x.ans = x.no1, x.no2;
}
...
struct data a;
a.no1 = 10;
a.no1 = 5;
a.pfAdd = add;
...
a.pfAdd(&a);
printf("Addition is %d\n", a.ans);
...
4) Consider a structure data which size s is very big. If we want to send a variable of this structure to another function better to send as reference. Because this will reduce the activation record(in stack) size created for the new function.
With Pointers - It will requires only 4bytes (in 32 bit m/c) or 8 bytes (in 64 bit m/c) in activation record(in stack) of function func
...
struct data a;
func(&a);
...
Without Pointers - It will requires s bytes in activation record(in stack) of function func. Conside the s is sizeof(struct data) which is very big value.
...
struct data a;
func(a);
...
5) We can change a value of a constant variable with pointers.
...
const int a = 10;
int *p = NULL;
p = (int *)&a;
*p = 5;
printf("%d", a); //This will print 5
...
in addition to the other answers, my comment about "string"-manipulating functions (string = zero terminated char array): always return the string parameter as a return value.
So you can use the function procedural or functional, like in printf("Dear %s, ", normal(buf));

Initializing local pointers by passing the address of a pointer

I see the following way of initializing a local pointer in almost every part of my code. want to understand the reason and intricacies in doing so.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void initialize_p(char **p)
{
char *p_local = NULL;
p_local=malloc(6);
strcpy(p_local,"sandy");
*p = p_local;
}
int main(void)
{
char *p = NULL;
initialize_p(&p);
printf("Name : %s\n",p);
return 0;
}
It is just that, i am showing here with simple string. And in my actual code, it is being done using structures.
I kind of understand the above logic and also I don't. Please clear the concept involved in the above style of implementing. Also, let me know if there is any other better way of doing the same.
Please Enlighten .. :)
I'd probably return the newly allocated string instead of passing a pointer to a pointer as an argument:
char *initialize(void) {
char *init = "sandy";
char *ret = malloc(sizeof(init)+1);
if (ret != NULL)
strcpy(ret, init);
return ret;
}
int main() {
char *p = initialize();
printf("Name: %s\n", p);
free(p);
return 0;
}
In initialize_p a chunk of memory is allocated and some string is copied into the memory. In order for the caller of initializer to get the address of this new chunk of memory the address of the pointer p is passed to initialize_p:
char **p
+---+---+---+---+---+----+
*p -> | s | a | n | d | y | \0 |
+---+---+---+---+---+----+
if only the *p would have been passed then setting the pointer inside the function would be the equivalent of:
void foo(int a)
{
a=3;
...
}
a better way would be to use strdup which does the same thing as you do in your function
char* initialize_p()
{
return strdup("sandy");
}
also make sure you free the string that is returned to avoid memory leak.
I'd suggest you to create allocation and deallocation function pair
char *createP()
{
char *p = NULL;
p=malloc(6);
strcpy(p,"sandy");
return p;
}
void freeP(char *p)
{
if (p) free(p);
}
int main(void)
{
char *p = createP();
printf("Name : %s\n",p);
freeP(p);
return 0;
}
Clearing the concept? Well, in such a simple case I don't see the point in operating with byref output parameters - for me, object-oriented-like structure constructor functions are easier to understand if they work like this:
struct foo *bar = myobj_new(); // uses malloc and returns a pointer
// do something with bar
myobj_destroy(bar); // uses free
Some agree that this design is good because then the return value of the function can be used as an error/success code (have you seen SQLite3?), but I disagree. I think the primary, the most important result of a function should go through the return value, and not some auxiliary stuff. (I tend to write libraries in which failure is indicated by returning NULL and setting a byref-passed error code).
The only valid scenario I can think of is when it's more logical or symmetrical to pass arguments like this. For example, imagining a very strange sort function which is similar to the C stdlib function qsort(), but requires its comparison function itself to make the swapping of two elements when needed. The comparison function obviously needs byref access to its two parameters in order to exchange them, but it may also be useful to return the originally encountered order to the caller sort function in order to optimize the algorithm. So this comparison function could be something like:
int compare(void *a, void *b)
{
int x = *(int *)a;
int y = *(int *)b;
if (x > y)
{
*(int *)a = y;
*(int *)b = x;
return +1;
} else if (x < x) {
return -1;
}
return 0;
}
Well, pretty much that's it about my opinion...
it's an out-parameter. the function produces a result for you, and saves it to the parameter you pass. this is often used when the size of the result may vary, or if the type of the parameter is Opaque.
Personally, I think returning the result is much clearer, and is less error-prone when a dynamic allocation is required (as seen in JerryCoffin's answer +1).
when a dynamic allocation is not required, then pass it by reference (as a non-const parameter) if it is not trivially small:
struct t_struct { int a[100]; };
void InitStruct(struct t_struct* pStruct) {
pStruct->a[0] = 11;
...
}
struct t_struct s;
void InitStruct(&s);
and if it is trivially small, you may consider returning by value.

Resources