Bregalad wrote:Oziphantom wrote:
I disagree. As sometimes I want to return multiple things from a function call, say bool myFunc(int param1, int* result) this allows me to get a result AND know if it succeed without having a magic unsafe value like INT_MIN.
In assembly, I do this all the time, and it's a trivial thing to do. I just use the A register for the result and the C flag indicates wether a correct result is returned. Couldn't be any simpler.
In C you have to ressort to a "hack" of passing a poitner to a function which is not a real argument, but a return value. This seriously hinder code readability. In addition this removes possibilities of optimisation. WHY, oh good lord why ? You just showed how terrible C is. If I could just return an "int, bool" pair, that'd be much better ! But C can only do that with structs, which are their own complicated thing in their own right.
What optimisation has been removed? Its not assembly there is not a 1:1 relationship between what you type and what is spat out. There is nothing to stop the C compiler from returning the Bool in C and *result in A. There is also nothing stopping it from inline the code such that it never returns anything and the Bool gets turned into a Jump or branch further down the code and the *result is just generated in A, an optimisation you will never get with a function in ASM. Maybe it decideds it is called so much that it puts a static variable to hold the value on the heap and thus just writes the value to that variable and all code there after loads from variable to save it from having to push and pop it on the stack multiple times, if your code needs to save and refer to the returned value a lot in the code that follows your calls. Just because something is in the function params or a return from a function doesn't mean it
has to be called or passed that way, the ABI can define a standard way, but the optimiser will do it any darn way it wants, as it seems to be most optimal for all cases it is used. However if you really want to nudge __fast_call will use Pascal passing as default over a default C, but I doubt compilers even listen to it any more either, but maybe they do in a debug build.
Also which of these is more readable
Code: Select all
returnValues = my_func(value)
if returnValues[0]:
print( returnValues[1]
or
Code: Select all
int funcValue = 0;
if (myFunc(param, &funcValue) )
{
printf("%d\n",funcValue);
}
much of a muchness? lets try a larger example
Code: Select all
returnValues = get_containing_rect(point1x,point1y,point2x,point2y,width1,height1,width2,height2)
if returnValues[0]:
collide_point(point_x,point_y,returnValues[1],returnValues[2],returnValues[3],returnValues[4])
or
Code: Select all
int rect_x =0, rect_y = 0, rect_width = 0, rect_height = 0;
if( get_containing_rect(point1x,point1y,point2x,point2y,width1,height1,width2,height2,&rect_x,&rect_y,&rect_width,&rect_height)
{
collide_point(point_x,point_y,rect_x,rect_y,rect_width,rect_height) ;
}
the C case ( and in the 2nd case use a struct ) has named things for each param the earlier case has magic numbers that index into something to pull something out. The named version is going to be a lot easier to read and maintain. Also in the C case the compiler can put 2 dummies on the stack, then push the rect_x,rect_y,rect_width,_rect_height, thus when it wants to call collide_point it just overwrites the dummies with point_x and point_y and optimises the push and pull away. as poping 4 or 6 things off the stack takes the same amount of time. Which it can't do in the multiple return case as you have fixed index looks up in the array, I mean it can modify the index to switch over if it has put each item on the stack and not put an object on the stack that is a real list or something...
Bregalad wrote:
This does give me more control as now I can pass
Code: Select all
int
int*
int**
const int
const int*
const int**
int* const
int** const
const int* const
const int** const
const int*const*
const int*const* const
You just summarized how broken C is in a few lines. This garbage basically don't even look like code.
Why is being able to strictly control what a function can and can't do to a variable broken. It alows you to make the definition exact and binding, it allows you to get the compiler to catch bugs for you, the static analyser to help find issues, it allows you to make code thread safe. Its when you get to a language that has seemingly random rules on what does change something passed in and what won't change. See Python, String can't change, List can change , Tuple can't change, dictionary can change, Byte array can't change, byteArray can change. In C it is explicit and written in the prototype for all to see and if you try to break it, the compiler will stop you. Not give you a random crash when person clicks button C then D, then A then F.