简体   繁体   中英

Compiler Optimization: const on non-pointer function arguments in C

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 const s 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM