Live data from Hacker News

Why Const Doesn't Make C Code Faster

theartofmachinery.com

91–100 of 197 posts

Re: Why Const Doesn't Make C Code Faster

#91
Well, of course:

  void constByArg(const int *x)
  {
    printf("%d\n", *x);
    constFunc(x);
    printf("%d\n", *x);
  }
Here, the object referenced by pointer x is non-local, and so is constFunc.

The object could be modified in legal ways nothing to do with constFunc stripping away the qualifier.

Also, if the object is not defined const, then constFunc is allowed to do that, too.

Then the next, correct, example with a const protected local shows that two instructions are shaved off. That's a wortwhile saving that could be leveraged to get faster code.

If you're passing local variables into helper functions which are not supposed to change them, you can shave off some cycles with const.

> I mean, I removed const from the entire program

Maybe sqLite doesn't use const specifically with a view toward optimization. To see an overall performance impact, there would have to be some case in a "hot spot" of the program, where const is used with some local variables being passed into functions. (Or whatever other case we can ferret out where const happens to help.)

There are some widely applicable optimizations which scoop up all the "low hanging fruit" improvements, but after that, optimization is a game of eking out small gains with specialized cases.

Re: Why Const Doesn't Make C Code Faster

#92
post #4
post #2

overlooks the value of const qualification for the caller - if the argument is marked as const, the caller might reasonably assume the data won’t be changed.

Yes, there are many cases where the caller can optimize the dependency chain / order of constFoo(x); constBar(x); where it couldn't make that assumption if one function wasn't const.

Unfortunately, C++ const functions are not necessarily pure functions and cannot be freely reordered.

Re: Why Const Doesn't Make C Code Faster

#94
post #82
post #76

// x is just a read-only pointer to something that may or may not be a constant void constFunc(const int *x) Is that correct? I read that as “x is a pointer to a const int” If you want “x is a read-only pointer to an int”, you would need void constFunc(int * const x) The article also doesn’t mention the case “x is a read-only pointer to a constant int”. To state that, you would use void constFunc(const int * const x)…

I believe the distinction they’re making is that there is actually no guarantee that the value pointed to by x will remain constant. All this tells you is that you’re not allowed to use x to make the modification. Consider: int foo = 42; const int *x = &foo; foo = 43;

Restrict keyword does do that if you wish to say that to the compiler. It tells it that no parameters point to the same memory. So if you won't change things via x, *x won't change.

Re: Why Const Doesn't Make C Code Faster

#95

Earlier quoted context omitted.

D has a `pure` attribute for functions, and yes it is enforced. It's enforced even to the point where it becomes a PITA, but when you manage to make functions pure, you know it's solid. One pain point with pure functions is you can't insert debug logging statements. D has a special case for that - purity for a statement isn't checked if it is prefixed with the `debug` keyword: pure int square(int x) { debug printf("c…

This means you can't re-order the computation, though, or memoize it—at least not the the extent it's possible without IO.

The use of the debug {} block in D is opt-in e.g. the compiler only includes those statements when given the debug flag

https://d.godbolt.org/z/Rwu4Cq (remove "-d-debug" to see)

Re: Why Const Doesn't Make C Code Faster

#96
post #90
post #86

Earlier quoted context omitted.

I wonder does that mean you could also enforce freeing memory allocated by a pure function as well?

I'm not sure what you mean? Allocators are often pure in D, they probably shouldn't be but that would mean allocating outside the function which would be ugly and probably buggy too

Obviously a pure function can allocate memory on the stack. I would think it could also allocate memory on the heap, iff it was guaranteed that the memory was freed before the function exits. Was thinking that would be something the compiler would do.

Forgive me I'm just a small brained firmware programmer.

Re: Why Const Doesn't Make C Code Faster

#97
I once had a very stubborn intern who decided to add as much const as he could in our codebase. What followed was a heated discussion and I did a global replace of const by nothing.

The main problem with const is that it's ugly, it's viral and it does not add any value to the code.

And I know all the supposedly good things about this, but I never found any real usage in practice.

Re: Why Const Doesn't Make C Code Faster

#98
post #89

Const does make C go faster, just not in most of the places you see it used. For const to help, the object itself needs to be defined const. Just taking a `const object * ` (or `const object&` in C++) doesn't help you determine the constness of the underlying object, and that usually accounts for the majority of const usage by volume. Limiting the scope to of actual const definitions , it can help a lot, but only in…

BINGO!!! The pointer is constant, not the item being pointed to. Since you’re dereferencing the pointer, i.e. accessing the non-const bits, the compiler must reload.

The examples in the articles are non-constant pointers to constant data. If you want to declare the pointer itself const, you need to do it after the asterisk.

    const int* const 
instead of

    const int*

Re: Why Const Doesn't Make C Code Faster

#99
post #77
post #60

Earlier quoted context omitted.

Cast away const. One of the many reasons I gave up on C++. What is const if it can be cast away?

const should have been renamed to readonly, because that's what it means. It means that a variable only has readonly access to a value, but it is possible that another variable has write permissions, and so a compiler can not assume that just because one variable has readonly permission, that all variables have readonly permission except for in very limited circumstances.

readonly was the original proposed name, if I remember my D&E [0] correctly. Bjarne outlined in that book why he went with const instead, but I forget why off the top of my head. I guess it's tine for a re-read!

[0] The Design and Evolution of C++

Re: Why Const Doesn't Make C Code Faster

#100
post #88

I think the big problem here is that const doesn't really truly say anything about aliasing. Even excluding casting evils, calling a method with a const pointer only means that the method isn't supposed to change the value. It does not mean that the caller isn't going to change things (particularly from another thread). The languages are simply too permissible when it comes to what a pointer means and how it can be u…

Even excluding casting evils, calling a method with a const pointer only means that the method isn't supposed to change the value. It does not mean that the caller isn't going to change things (particularly from another thread). This is incorrect. Actually, you promise not to change things from another thread, DMA, interrupt handler, signal, etc, with any non-volatile reference passed, let alone a const! The compiler…

Your comment is incorrect as well.

The C specification describes semantics in terms of an abstract machine which is actually quite different from real hardware (most notably in terms of how memory works!). It then goes on to say that the compiler may choose to implement it radically differently, so long as the observable semantics (I/O calls and volatile accesses) are preserved. I'd have to double check whether it was C or C++ that said that the compiler is free to assume that infinite loops do not exist.

> Actually, you promise not to change things from another thread, DMA, interrupt handler, signal, etc, with any non-volatile reference passed, let alone a const!

This is not the case. The C specification requires that you use volatile to indicate that code outside of the C execution model may access the memory location. Of your list, only DMA and interrupt handlers are outside the execution model; signal handlers and threads are both considered inside the memory model. The only way for a signal handler to communicate with code outside the signal handler is with volatile sig_atomic_t; volatile int does not cut it. To communicate between threads, you need to ensure proper synchronization. This may involve the use of locks, fences, or atomics with appropriate orderings chosen.

> The compiler loads things into registers and has no way to know if memory in a passed reference changes underneath the hood

To be pedantic, the compiler relies on undefined behavior here. It is undefined behavior if you cause the value to be changed in a way that violates these rules, so the compiler has absolutely no restrictions on what may happen in such executions.

> If you've ever head about how "double check locking" is an antipattern, this is a big part of why.

This has absolutely nothing to do with why double-checked locking is incorrect. Double-checked locking is problematic in large part because of hardware reordering of loads and stores. In general, you need a store barrier to guarantee that all of the modifications the first thread changed has been made visible to other processors followed by a load barrier to guarantee that all prior modifications from other processors have been made visible to the second thread. Volatile does absolutely nothing to provide these barriers (except if you use MSVC, which documents that they treat volatile variables as equivalent to acquire/release semantics on x86 because regular loads and stores on x86 have those semantics anyways--this is nonportable behavior). The double-checked locking pattern does not provide a load barrier in the second thread, which means the ordering semantics are not guaranteed. If you use atomic loads and stores when implementing double-checked locking, you do get the necessary semantics for correctness.

Post reply on HN