__attribute__((const)) vs __attribute__((pure)) in GNU C
Asked Answered
M

3

55

What is the difference between __attribute__((const)) and __attribute__((pure)) in GNU C?

__attribute__((const)) int f() {
    /* ... */
    return 4;
}

vs

__attribute__((pure)) int f() {
    /* ... */
    return 4;
}
Mattheus answered 18/3, 2015 at 9:5 Comment(2)
This may help.Mafia
Also see Implications of pure and constant functions on LWN.Jive
S
41

The difference is explained in the GCC manuals. Most notably a const function may only use the arguments passed in and not any memory, whereas a pure function can access memory too, under constraints:

The pure attribute prohibits a function from modifying the state of the program that is observable by means other than inspecting the function’s return value. However, functions declared with the pure attribute can safely read any non-volatile objects, and modify the value of objects in a way that does not affect their return value or the observable state of the program.

The __attribute__ ((pure)) means that the function has no side effects and the value returned depends on the arguments and the state of global variables. Therefore it is safe for the optimizer to elide some calls to it, if the arguments are the same, and the caller did not do anything to change the state of the globals in between the calls.

The __attribute__ ((const)) means that the return value is solely a function of the arguments, and if any of the arguments are pointers, then the pointers must not be dereferenced.

A const function is always pure.

Examples of const functions would be the abs functions from <stdlib.h> and some mathematical functions from <math.h>: sqrt, exp, etc. (Though they might be subject to rounding modes).

Examples of pure but non-const functions would be such functions as strlen - as it dereferences the pointer passed in.

Samuel answered 1/1, 2018 at 15:51 Comment(9)
Judging from what the optimizer does, a pure function may not access any global variables who's state can be changed by factors external to the control flow in which the pure function appears. So, global variables that are mapped to a device state, or ones that might be modified by another thread, and so on.Alethaalethea
Yes, the distinction between the 2 is rather that if the caller did modify a global then a pure function can change its return valueNari
After all the attribute is a signal for the caller, and the caller can not know the state of all memory-mapped variables in existence :DNari
New wording: "and caller did not do anything to change the state of the globals in between the calls."Nari
I think borrowing the documentation and saying `a function isn't pure if it accesses volatile variables' would be better.Alethaalethea
Argh link b0rken. @Alethaalethea apparently it has changed quite recently and it is much better than the time that I wrote the answer; this is the one from the time I was answering the questionNari
The question is about C, but the attribute is also available in C++. It's worth stating explicitly that in C++, reading const references is also prohibited if the referenced memory might ever change between calls (explanation).Snuffer
@Snuffer "const functions should never take pointer or, in C++, reference arguments." - that's quite not true, they could take pointer arguments, for example "is this pointer pointing to an address divisible by 4", and for references in C++ you could still use the address-of operator on the reference to do the same...Nari
sqrt and exp are NOT pure functions according to the attribute definition. They both may modify one global memory: errno. They do so when domain error and range error, respectively, occur.Tanner
P
51

From the documentation for the ARM compiler (which is based on gcc):

__attribute__((pure)) function attribute
Many functions have no effects except to return a value, and their return value depends only on the parameters and global variables. Functions of this kind can be subject to data flow analysis and might be eliminated.

__attribute__((const)) function attribute
Many functions examine only the arguments passed to them, and have no effects except for the return value. This is a much stricter class than __attribute__((pure)), because a function is not permitted to read global memory. If a function is known to operate only on its arguments then it can be subject to common sub-expression elimination and loop optimizations.

So, TL;DR: __attribute__((const)) is the same as __attribute__((pure)) but without any access to global variables.

Privily answered 18/3, 2015 at 9:11 Comment(3)
Note that ARM compiler also provides a __pure function qualifier, which is stricter than the pure attribute, and is equivalent to the const attribute.Hagberry
Also worth noting is the note about pointer arguments in the GCC doc: Note that a function that has pointer arguments and examines the data pointed to must not be declared constSemipalmate
@Semipalmate IMO const would be OK if the pointer points to read-only data, e.g. if it is a string literal.Naomanaomi
S
41

The difference is explained in the GCC manuals. Most notably a const function may only use the arguments passed in and not any memory, whereas a pure function can access memory too, under constraints:

The pure attribute prohibits a function from modifying the state of the program that is observable by means other than inspecting the function’s return value. However, functions declared with the pure attribute can safely read any non-volatile objects, and modify the value of objects in a way that does not affect their return value or the observable state of the program.

The __attribute__ ((pure)) means that the function has no side effects and the value returned depends on the arguments and the state of global variables. Therefore it is safe for the optimizer to elide some calls to it, if the arguments are the same, and the caller did not do anything to change the state of the globals in between the calls.

The __attribute__ ((const)) means that the return value is solely a function of the arguments, and if any of the arguments are pointers, then the pointers must not be dereferenced.

A const function is always pure.

Examples of const functions would be the abs functions from <stdlib.h> and some mathematical functions from <math.h>: sqrt, exp, etc. (Though they might be subject to rounding modes).

Examples of pure but non-const functions would be such functions as strlen - as it dereferences the pointer passed in.

Samuel answered 1/1, 2018 at 15:51 Comment(9)
Judging from what the optimizer does, a pure function may not access any global variables who's state can be changed by factors external to the control flow in which the pure function appears. So, global variables that are mapped to a device state, or ones that might be modified by another thread, and so on.Alethaalethea
Yes, the distinction between the 2 is rather that if the caller did modify a global then a pure function can change its return valueNari
After all the attribute is a signal for the caller, and the caller can not know the state of all memory-mapped variables in existence :DNari
New wording: "and caller did not do anything to change the state of the globals in between the calls."Nari
I think borrowing the documentation and saying `a function isn't pure if it accesses volatile variables' would be better.Alethaalethea
Argh link b0rken. @Alethaalethea apparently it has changed quite recently and it is much better than the time that I wrote the answer; this is the one from the time I was answering the questionNari
The question is about C, but the attribute is also available in C++. It's worth stating explicitly that in C++, reading const references is also prohibited if the referenced memory might ever change between calls (explanation).Snuffer
@Snuffer "const functions should never take pointer or, in C++, reference arguments." - that's quite not true, they could take pointer arguments, for example "is this pointer pointing to an address divisible by 4", and for references in C++ you could still use the address-of operator on the reference to do the same...Nari
sqrt and exp are NOT pure functions according to the attribute definition. They both may modify one global memory: errno. They do so when domain error and range error, respectively, occur.Tanner
C
3

Note that if a function is passed a pointer and examines the contexts of that pointer, it cannot be declared const, even if the passed pointer and the pointer contexts are const. This is a severe limitation to the usefulness of const.

You can return multiple values in C by using a struct, which makes it easier to use pure. (It is more typical to use pointer return operands, but this breaks use of pure).

Cropland answered 26/5, 2019 at 2:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.