How does compilers optimizes theese 4 types of function definitions. Is there any optimization done in sense of argument passing?
int check_collision(const SDL_Rect const *A,const SDL_Rect const *B) { ... }
int check_collision(SDL_Rect const *A,SDL_Rect const *B) { ... }
int check_collision(const SDL_Rect *A, SDL_Rect const *B) { ... }
int check_collision(SDL_Rect *A, SDL_Rect *B) { ... }
And if it matters, what do you think would be the preferable way of passing read only arguments to a function in cases where these argument might inefficent to copy when calling the funcion?
Use const in any of these cases to indicate the purpose of your usage more clearly and writing more readable code, modern day compilers are efficient and smart enough to apply required optimization's whether you pass the function argument as const or not.
In short, use const in this case for readability & preventing usage errors, & not for compiler optimization,
Compiler is smart enough to take care of that.
Note that your first three declarations are effectively all the same, even if SDL_Rect is a typedef (because the const keyword never "penetrates" a typedef, as I like to put it).
The const keyword acts in different ways in different places. In this case it merely makes a (revocable) promise that check_collision will not alter or replace *A (nor A[i] for any i), nor *B (nor B[j] for any j). However, it's possible that A[i] and/or B[i] are modified by any function that your code calls, because the underlying objects may be modifiable and some other function might know how to access them. The C99 keyword "restrict" tells the compiler that this is not the case, and provides a lot of opportunities to optimize; it's usually what you want here.
C99 also adds a new use for the "static" keyword to enable certain compile-time optimizations that go above and beyond those provided by "restrict". These apply only when the pointers point to the first element of arrays whose size is at least some knowable value. (It's meant for vectorization, mainly.)
As #Als noted, it's best to start with the simplest statement of "what you mean" and only add optimization keywords if you discover that the program is taking a lot of time in some particular part(s) of the program.
Related
It is common to see the keyword const with pointers :
void function(const char *string)
{
const char *other_string = "some string";
}
But why do not we use const every time we declare a variable that we will not change ? It is rare to see :
void function(const int i)
{
const double j = 1.2;
// i and j will not be changed in this function
}
I am trying to understand why we do not use const more often, is it always a good thing to use it when we can, or not ?
This post seems to answer YES, but in reality this doest not seem to be the case ...
In most cases it no longer makes a difference.
Often enough the compiler will be able to deduce that the variable is actually read only, and treat it as a constant during optimization.
Either way, you usually use const consequently on things like const char *string in order to avoid accidentally modifying the parameter.
Since all parameters are passed by value, this isn't something which can't happen for an integer. Only for pointers the pointer itself is the value.
Actually, const char *string isn't fully constant either yet. Only the chars the pointer is pointing to is, but the pointer as a variable isn't. It would only become when specifying it as const char * const string. Now the string variable is completely constant for the scope of the function.
In the case you give, I would always say
void function(const int i)
in a situation where the role of i is to parameterise the behaviour of the function -- which is almost always. If I change i in the body of the function, I have either made an error, or written something which another person will find hard to understand later.
Intentionally modifying the value of i in the function isn't as "dangerous" as modifying a entity through its pointer -- it won't create side-effects outside the function. I guess that's why most developers don't feel the pressure to define primitive paramters as const. I maintain, however, that it is a sensible thing to do, if one cares about long-term maintenance.
In your second example, the parameter is passed by value, making it const basicly has no meaning. const is most handy when passing parameters by reference.
There is another problem with const known as "const poisoning". Consider the following:
int foo(char * str, int n)
{
...
bar(str);
...
}
If we make str to be const, we must then ensure that bar also takes a const etc. (which can affect multiple files and modules). This is especially painful if you're editing old and inconsistent code (not always the case, but should be considered).
For example:
int f1() {
return 3;
}
void f2(int *num) {
*num = 3;
}
int n1, n2;
n1 = f1();
f2(&n2);
With f1, we can return a value and do "variable=f1()"
But the same can be done with a void function that updates the value of that variable given its address without having to do "variable=f1()".
So, does this mean that we can actually just use void functions for everything? Or is there something that a void function cannot do to replace another int function/(type) function?
The main problem with making everything a void function (which in some people's lexicon is called a "routine") is that you can't chain them easily:
f(g(x))
becomes, if you really want to chain it:
int gout;
f((g(x, &gout), gout))
Which is painful.
Yes you could use void return types for everything and rely exclusively on returning via modified parameters. In fact, you could avoid using functions entirely and put everything in your main method.
As with any other feature of the language, return values give you particular advantages, and its up to you to decide if you want them. Here are some advantages of return values off the top of my head:
Returned values can be assigned to const variables, which can make your code easier to reason about
Certain types of optimisation can be applied by the compiler for returned values (this is more applicable to C++ RVO but may also apply to C's structs; I'm not sure)
Code which uses returned values is often easier to read, especially when the functions are mathematical (e.g. imagine having to declare all the temporaries manually for a large mathematical operation using sin/cos/etc. if they required the output to be via parameters). Compare:
double x = A*sin(a) + B*cos(b);
with
double tmpA, tmpB;
sin(&tmpA, a);
cos(&tmpB, b);
double x = A * tmpA + B * tmpB;
or to use a similar structure as John Zwinck suggested in his answer:
double tmpA, tmpB;
double x = A * (sin(&tmpA, a), tmpA) + B * (cos(&tmpB, b), tmpB);
It is guaranteed that the value will be set no matter what happens inside the function, as this is enforced by the compiler (except some very special cases such as longjumps)
You do not need to worry about checking if the assigned value is used or not; you can return the value and if the requester doesn't need it, they can ignore it (compare this to needing NULL-checks everywhere in your alternative method)
Of course there are also disadvantages:
You only get a single return value, so if your function logically returns multiple types of data (and they can't logically be combined into a single struct), returning via parameters may be better
Large objects may introduce performance penalties due to the need to copy them (which is why RVO was introduced in C++, which makes this much less of an issue)
So, does this mean that we can actually just use void functions for everything?
Indeed. And as it turn out, doing so is a fairly common coding style. But rather than void, such styles usually state that the return value should always be reserved for error codes.
In practice, you usually won't be able to stick to such a style consistently. There are a some special cases where not using the return value becomes inconvenient.
For example when writing callback functions of the kind used by standard C generic functions bsearch or qsort. The expect a callback of the format
int compare (const void *p1, const void *p2);
where the function returns less than zero, more than zero or zero. Design-wise it is important to keep the parameters passed as read-only, you wouldn't want your generic search algorithm to suddenly start modifying the searched contents. So while there is no reason in theory why these kind of functions couldn't be of void return type too, in practice it would make the code uglier and harder to read.
Of course you could; but that does not make it a good idea.
It may not always be convenient or lead to easy to comprehended code. A function returning void cannot be used directly as an operand in an expression. For example while you could write:
if( f1() == 3 )
{
...
}
for f2() you would have to write:
f2( &answer ) ;
if( answer )
{
...
}
Another issue is one of access control - by passing a pointer to the function you are giving that function indirect access to the caller's data, which is fine so long as the function is well behaved and does not overrun. A pointer may refer to a single object or an array of objects - the function taking that pointer has to impose appropriate rules, so it is intrinsically less safe.
Modern compilers can optimize code when they see a const. However, I've never seen the C standard library use const for its non-pointer arguments. For example memcmp() is an example of this. It has 2 const void * arguments, but its third argument is size_t.
Why is the standard library (and other libraries) designed this way? Why don't I see const size_t or const int in modern code?
C uses call-by-value. It does not help the compiler one bit to mark a function argument as const (note that none of the arguments of memcmp() is const. The pointers arguments could also be declared const, and you could have suggested that they should be: int memcmp(const void * const s1, const void * const s2, size_t const n);. But they aren't).
The reason it would not help the compiler to mark function arguments const is that a function argument is just, from the point of view of the function, a local variable. As long as the function does not take its address, it's very easy for the compiler to see that the variable is never modified.
In contrast, the const modifiers that are part of memcmp()'s prototype (const void *s1)
are part of its contract: they express that the function does not modify the pointed data. The const modifier is never used this way for the argument themselves because the caller does not care if the function modify its arguments: they are just copies (again because C uses call-by-value).
Those consts mean different things. In
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
const void * ptr1 means that memcmp will treat ptr1 as pointing to constant data and won't modify it; similarly for const void * ptr2. Thus, the caller knows that the stored values won't be changed and can optimize accordingly. In a function call like
int result = memcmp(ptr1, ptr2, num);
the variables ptr1, ptr2, and num are copied into the function. memcmp makes no promises not to adjust them; it only promises not to adjust what the pointers point to. Indeed, it might increment/decrement any of the copied variables in order to step through the arrays if that proves efficient. If it wanted to promise not to change any of them, the declaration would be:
int memcmp ( const void *const ptr1, const void *const ptr2, const size_t num );
For simple data types (like pointers and integers), little (if any) optimization can be gained in this way, and the original specifiers of this function (and others) apparently saw no reason to prevent implementations from modifying the variables in fortuitous circumstances.
Main reason for this is Library consistency. Changing a size_t argument to a const size_t will require libraries that do modify the size to be rewritten. Not all implementations of a library need to use the same algorithm. This is the main reason why existing library functions are not being adapted.
New library functions are often created purposefully with non const arguments so that certain machine dependent implementations can use the modifiable argument.
For instance the Intel C++ Compiler version of memcmp actually counts down the length argument during execution. Some other implementations may not do so.
gcc 4.4.4 c89
I am just wondering is it worth passing a const into a function.
i.e.
void do_something(const char *dest, const int size)
The size is a read-only so I don't want to change it. However, some developers never have this as const has it is a local copy that is being used. The pointer is const as you can change the value in the calling routine.
I always have a const on read-only local copies, as it confirms to anyone reading my code that it is a read-only variable. And also, when coding I don't make the mistake of changing it without realizing.
Many thanks for any suggestions,
People's opinion differ on this. I know some perfectly capable developers who write that const for any parameter that should not be changed locally in the function. Logically that is just consequent application of the const-correctness principle.
Whatever you do, however, you should omit the const in the function declaration in the header. The const should be part only in the function definition. C (and C++, too) has rules that make this compatible (i.e a const for a value parameter is ignored (when it affects the parameter only at its toplevel) for pure function declarations that don't have a body). The rationale is that such a const will not change anything with regard to the caller, and is thus an implementation detail of the called function.
This does not hold for your first parameter. Any capable developer i know will put that const there, because it's making an important guarantee to the caller of your function (that it won't change the data pointed to of what is passed in). The name of your parameter, however, seems a bit odd, because it indicates that the function does need to write into what is pointed to.
Notice that to be consequent, you would have to make the first parameter itself const too, like you did with the second parameter. Thus this would become (renaming it to "source" too, to avoid confusion).
void do_something(const char * const source, const int size)
Personally, I like putting const on as many variables as possible – I rarely change the value of a variable once assigned. (One notable exception are of course loop counters/iterators.)
At the very least, this significantly improves debuggability because it ensures that values cannot be changed. This makes tracking the state of the execution much easier. It also improves readability because it signals the intent of working with immutable values.
Consequently, I do the same for function parameters. After all, they behave like normal variables inside the function.
On the other hand, this confuses the hell out of many other programmers so in most collaborative projects I refrain from doing this; it would break consistency and be counter-productive.
The so called "const correctness" is very important especially if you are creating some module (dll for example) where other people will use it. It makes it much easier to understand the purpose of the function and helps prevent some odd bugs (among other things). So yes, i would definetly suggest using the const modifier where applicable.
EDIT: now looking closely at the function header, it seems that "dest" is something which the function has to change. Then declaring it as const seems odd.
In my opinion there is no point in declaring const on anything else than a pointed area. Scalar parameters (and even pointers) are local copies with the exact same constraints as other local variables. They are in fact local variables and it's sometime appropriate to use them and modify them which may avoid unecessary copies of their values.
char * strcat(char *d, const char *s)
{
char *p = d;
while(*p) p++;
while(*s) *p++ = *s++;
*p = 0;
return d;
}
char * strcat(char *d, const char *s)
{
char *p = d;
const char *s2 = s;
while(*p) p++;
while(*s2) *p++ = *s2++;
*p = 0;
return d;
}
Is the second variant really better? I don't think so.
When using the old K&R syntax it's more obvious that they are local variables of the function.
char * strcat(d, s)
char *d;
const char *s;
{
...
Our static analysis tool complains about a "useless type qualifier on return type" when we have prototypes in header files such as:
const int foo();
We defined it this way because the function is returning a constant that will never change, thinking that the API seemed clearer with const in place.
I feel like this is similar to explicitly initializing global variables to zero for clarity, even though the C standard already states that all globals will be initialized to zero if not explicitly initialized. At the end of the day, it really doesn't matter. (But the static analysis tool doesn't complain about that.)
My question is, is there any reason that this could cause a problem? Should we ignore the errors generated by the tool, or should we placate the tool at the possible cost of a less clear and consistent API? (It returns other const char* constants that the tool doesn't have a problem with.)
It's usually better for your code to describe as accurately as possible what's going on. You're getting this warning because the const in const int foo(); is basically meaningless. The API only seems clearer if you don't know what the const keyword means. Don't overload meaning like that; static is bad enough as it is, and there's no reason to add the potential for more confusion.
const char * means something different than const int does, which is why your tool doesn't complain about it. The former is a pointer to a constant string, meaning any code calling the function returning that type shouldn't try to modify the contents of the string (it might be in ROM for example). In the latter case, the system has no way to enforce that you not make changes to the returned int, so the qualifier is meaningless. A closer parallel to the return types would be:
const int foo();
char * const foo2();
which will both cause your static analysis to give the warning - adding a const qualifier to a return value is a meaningless operation. It only makes sense when you have a a reference parameter (or return type), like your const char * example.
In fact, I just made a little test program, and GCC even explicitly warns about this problem:
test.c:6: warning: type qualifiers ignored on function return type
So it's not just your static analysis program that's complaining.
You can use a different technique to illustrate your intent without making the tools unhappy.
#define CONST_RETURN
CONST_RETURN int foo();
You don't have a problem with const char * because that's declaring a pointer to constant chars, not a constant pointer.
Ignoring the const for now, foo() returns a value. You can do
int x = foo();
and assign the value returned by foo() to the variable x, in much the same way you can do
int x = 42;
to assign the value 42 to variable x.
But you cannot change the 42 ... or the value returned by foo(). Saying that the value returned from foo() cannot be changed, by applying the const keyword to the type of foo() accomplishes nothing.
Values cannot be const (or restrict, or volatile). Only objects can have type qualifiers.
Contrast with
const char *foo();
In this case, foo() returns a pointer to an object. The object pointed to by the value returned can be qualified const.
The int is returned by copy. It may be a copy of a const, but when it is assigned to something else, that something by virtue of the fact that it was assignable, cannot by definition be a const.
The keyword const has specific semantics within the language, whereas here you are misusing it as essentially a comment. Rather than adding clarity, it rather suggests a misunderstanding of the language semantics.
const int foo() is very different from const char* foo(). const char* foo() returns an array (usually a string) whose content is not allowed to change. Think about the difference between:
const char* a = "Hello World";
and
const int b = 1;
a is still a variable and can be assigned to other strings that can't change whereas b is not a variable. So
const char* foo();
const char* a = "Hello World\n";
a = foo();
is allowed but
const int bar();
const int b = 0;
b = bar();
is not allowed, even with the const declaration of bar().
Yes. I would advise writing code "explicitly", because it makes it clear to anyone (including yourself) when reading the code what you meant. You are writing code for other programmers to read, not to please the whims of the compiler and static analysis tools!
(However, you do have to be careful that any such "unnecessary code" does not cause different code to be generated!)
Some examples of explicit coding improving readability/maintainability:
I place brackets around portions of arithmetic expressions to explicitly specify what I want to happen. This makes it clear to any reader what I meant, and saves me having to worry about (or make ay mistakes with) precedence rules:
int a = b + c * d / e + f; // Hard to read- need to know precedence
int a = b + ((c * d) / e) + f; // Easy to read- clear explicit calculations
In C++, if you override a virtual function, then in the derived class you can declare it without mentioning "virtual" at all. Anyone reading the code can't tell that it's a virtual function, which can be disastrously misleading! However you can safely use the virtual keyword: virtual int MyFunc() and this makes it clear to anyone reading your class header that this method is virtual. (This "C++ syntax bug" is fixed in C# by requiring the use of the "override" keyword in this case - more proof if anyone needed it that missing out the "unnecessary virtual" is a really bad idea)
These are both clear examples where adding "unnecessary" code will make the code more readable and less prone to bugs.