When I attempt to run this code as it is, I receive the compiler message "error: incompatible types in return". I marked the location of the error in my code. If I take the line out, then the compiler is happy.
The problem is I want to return a value representing invalid input to the function (which in this case is calling f2(2).) I only want a struct returned with data if the function is called without using 2 as a parameter.
I feel the only two ways to go is to either:
make the function return a struct pointer instead of a dead-on struct but then my caller function will look funny as I have to change y.b to y->b and the operation may be slower due to the extra step of fetching data in memory.
Allocate extra memory, zero-byte fill it, and set the return value to the struct in that location in memory. (example:
return x[nnn];
instead ofreturn x[0];
). This approach will use more memory and some processing to zero-byte fill it.
Ultimately, I'm looking for a solution that will be fastest and cleanest (in terms of code) in the long run. If I have to be stuck with using ->
to address members of elements then I guess that's the way to go.
Does anyone have a solution that uses the least cpu power?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
long a;
char b;
}ab;
static char dat[500];
ab f2(int set){
ab* x=(ab*)dat;
if (set==2){return NULL;}
if (set==1){
x->a=1;
x->b='1';
x++;
x->a=2;
x->b='2';
x=(ab*)dat;
}
return x[0];
}
int main(){
ab y;
y=f2(1);
printf("%c",y.b);
y.b='D';
y=f2(0);
printf("%c",y.b);
return 0;
}
If you care about speed, it is implementation specific.
Notice that the Linux x86-64 ABI defines that a
struct
of two (exactly) scalar members (that is, integers, doubles, or pointers, -which all fit in a single machine register- but notstruct
etc... which are aggregate data) is returned thru two registers (without going thru the stack), and that is quite fast.BTW
is obviously wrong. You could code:
Also,
looks suspicious to me (since you
return x[0];
later). You are not guaranteed thatdat
is suitably aligned (e.g. to 8 or 16 bytes), and on some platforms (notably x86-64) ifdat
is misaligned you are at least losing performance (actually, it is undefined behavior).BTW, I would suggest to always return with instructions like
return (aa){l,c};
(wherel
is an expression convertible tolong
andc
is an expression convertible tochar
); this is probably the easiest to read, and will be optimized to load the two return registers.Of course if you care about performance, for benchmarking purposes, you should enable optimizations (and warnings), e.g. compile with
gcc -Wall -Wextra -O2 -march=native
if using GCC; on my system (Linux/x86-64 with GCC 5.2) the small functionis compiled (with
gcc -O2 -march=native -fverbose-asm -S
) into:you see that all the code is using registers, and no memory is used at all..
I would use the return value as an error code, and the caller passes in a pointer to his
struct
such as: