Stories
Slash Boxes
Comments

SoylentNews is people

posted by Fnord666 on Sunday August 25 2019, @01:57PM   Printer-friendly
from the quite-the-contrary dept.

Submitted via IRC for SoyCow3196

Why const Doesn't Make C Code Faster

In a post a few months back I said it's a popular myth that const is helpful for enabling compiler optimisations in C and C++. I figured I should explain that one, especially because I used to believe it was obviously true, myself. I'll start off with some theory and artificial examples, then I'll do some experiments and benchmarks on a real codebase: Sqlite.

Let's start with what I used to think was the simplest and most obvious example of how const can make C code faster. First, let's say we have these two function declarations:

void func(int *x);
void constFunc(const int *x);

And suppose we have these two versions of some code:

void byArg(int *x)
{
  printf("%d\n", *x);
  func(x);
  printf("%d\n", *x);
}

void constByArg(const int *x)
{
  printf("%d\n", *x);
  constFunc(x);
  printf("%d\n", *x);
}

To do the printf(), the CPU has to fetch the value of *x from RAM through the pointer. Obviously, constByArg() can be made slightly faster because the compiler knows that *x is constant, so there's no need to load its value a second time after constFunc() does its thing. It's just printing the same thing. Right? Let's see the assembly code generated by GCC with optimisations cranked up:


Original Submission

 
This discussion has been archived. No new comments can be posted.
Display Options Threshold/Breakthrough Mark All as Read Mark All as Unread
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
  • (Score: 2, Interesting) by isj on Sunday August 25 2019, @03:10PM (9 children)

    by isj (5249) on Sunday August 25 2019, @03:10PM (#885200) Homepage

    I assume that many C/C++ programmers already knew that const doesn't necessarily improve performance. But it's still good that there is an article about it so younglings can learn - we old farts are not always that good at disseminating knowledge like that.

    I don't like that the article's first proof is the generated assembly, but I guess that quoting chapter and verse(s) from the C standard would have made most readers eyes glaze over. I think it would have been better to first show in source code why the compiler cannot assume that the pointed-to contents of a const pointer cannot change, then quote chapter and verse from the standard, then finally prove it with generated assembly.

    Starting Score:    1  point
    Moderation   0  
       Interesting=1, Overrated=1, Total=2
    Extra 'Interesting' Modifier   0  
    Karma-Bonus Modifier   +1  

    Total Score:   2  
  • (Score: 5, Informative) by Ethanol-fueled on Sunday August 25 2019, @03:32PM (4 children)

    by Ethanol-fueled (2792) on Sunday August 25 2019, @03:32PM (#885206) Homepage

    The point of const is to make variables immutable so people don't fuck with them, not optimize for speed.

    • (Score: 2, Informative) by Anonymous Coward on Sunday August 25 2019, @04:44PM (1 child)

      by Anonymous Coward on Sunday August 25 2019, @04:44PM (#885229)

      I was waiting for someone to point this out.

      Furthermore at least back in the DOS, proprietary unix and 8bit days, I seem to remember it providing other benefits that could speed things up, but it was a secondary effect mostly due to the optimization paths compilers of the day used.

      const's primary purpose has always been to ensure a pointer is immutable within the context of the C code itself. Writing in assembly could always bypass it and certain C compilers would fail to take it into account in all circumstances if you were particularly 'creative' with your means of access or rewriting of the pointer. But if you were following the standards for data typing, const was there to protect your functions or data structure from someone doing something stupid or malicious while working with a pointer or data structure.

      We used to call them clobbering vs non-clobbering functions which either modified in place, or had to create and return a new copy of a data structure with a new pointer in order to ensure consistency in the codebase. It was the tradeoff between memory consumption and ensuring a sane program state in the older memory constrained days of application and operating system development.

      • (Score: 2, Informative) by Anonymous Coward on Sunday August 25 2019, @06:49PM

        by Anonymous Coward on Sunday August 25 2019, @06:49PM (#885299)

        Look at his command line.

        gcc -S -Wall -O3 test.c

        That is the most aggressive optimization switch. Two of those are basic constant folding and basic constant propagation. When compiling, it can look and determine both of the variables, despite only one being marked, are not changed during actual execution and makes such a substitution, when it believes it is safe to do so. To your point, when GCC compilers were dumber "const" was important because it would signal the compiler you could handle the constants that way and it didn't have to guess whether or not it was safe.

        And that doesn't get into any other black magic the -O3 switch will do. If anything, he should have shown what a bare command line, -O, -O2, and -Os, all against the same code. He is smart enough to know the difference between a t test and a U test (although not that these are dependent samples and a different test should be used). I reckon he is smart enough to try and show the difference that way.

    • (Score: 0) by Anonymous Coward on Monday August 26 2019, @12:10AM

      by Anonymous Coward on Monday August 26 2019, @12:10AM (#885437)

      const doesn't necessarily make objects immutable though. The variable can be changed elsewhere. const instead specifies access permissions to a variable.

    • (Score: 0) by Anonymous Coward on Monday August 26 2019, @04:24PM

      by Anonymous Coward on Monday August 26 2019, @04:24PM (#885693)

      Yeah but that's why God had to invent const_cast to override the excessive use of const by others to protect us.

  • (Score: 2, Interesting) by Anonymous Coward on Sunday August 25 2019, @09:20PM (3 children)

    by Anonymous Coward on Sunday August 25 2019, @09:20PM (#885383)

    I once spent several weeks arguing with one of my fellow senior engineer's over this exact thing.

    I *SHOWED* him how it was not doing anything. He had spent 2 weeks putting 'const' all over the code. Before functions in the api, in params, ... everywhere.

    He was one of those show off programmers that 'knew better' than everyone else. Would just nod smugly when I showed him how very very very wrong he was. Then ignore the advice of anyone on the team then yell at them because they did not follow his style guide which was only in his head. Ignoring the one the team had already agreed to and was doc'd in the wiki.

    Fucker you wasted a whole sprint fucking around with this?! The API did not need to be changed because it did not match the style guide from your former company. In fact it did not match the current company you worked at style guide.

    If you can not tell me what it is doing to your code get the fuck rid of it. I am reverting your whole sprints work because it adds no new features and only makes using variables harder for little gain. You wasted 5 hours of my time because I thought you were competent. Not anymore as now I have to extra scrutinize what you are doing and have to instruct others to do the same.

    Considering how many F bombs I am dropping you may think I was upset about this. Yes. Yes I am. I am usually fairly easy going with most changes. Because they are usually just fine. But this one was just too much.

    Constexpr in C++ on the other had has *tons* of uses. But put a const in their alongside it? Well you can just kiss your pre-compiled optimizations goodbye as const is a value decided at runtime thing. More along this thing is set here in code once and never modified again. While constexpr you can figure it out at compile time.

    Const is for things like where you would do something like #define XYZ 2. That has its uses and a nice way to enforce type. But even then not always needed.
    Not for every parameter and every function you can lay your hands on.

    Now do not get me wrong const has its uses. It is a modifier that should be used when needed, not dictated by style.

    What riles me up is the style nazis have glommed ont this this as something that is 'better' with no real reasons as to what the expression actually does. This is not so much a big deal anymore but it even varies between compiler sets what it actually does. The spec says what it does not what the compiler should with the optimizer in this case other than a delineation point of what can be optimized. That portion is usually an assumption by the programmer. Usually it is wrong.

    • (Score: 5, Informative) by Immerman on Monday August 26 2019, @02:08PM (2 children)

      by Immerman (3985) on Monday August 26 2019, @02:08PM (#885633)

      I disagree. Const is a valuable modifier that should be applied to any function interface where you're accepting parameters by reference, unless you explicitly intend to modify those parameters.

      Not because it makes code faster. Not even because it guarantees that the parameters won't be changed (it's almost always a bad idea, but you can always cast away const). But because it establishes the contract between function and calling context that the parameters will not be changed. How else are you going to do that? A sentence in the function comments that will almost never be read, and won't invoke any compiler errors to warn you when the contract is broken?

      Not to mention the fact that if your function takes non-const parameters that it never intends to modify, then you've just made it impossible to call with const data. A simple example - you declare a function:
      int CountLetters(char* theString);
      And you can't do something simple like call that function as
      int c = CountLetters("Some String #$ with 7298 letters, spaces, punctuations, etc");

      Put that in a larger context where you might want to call that function from within another function that *does* formally establish the contract and... you can't. Not without casting away const on the big fugly data object your own function asserted it would not modify. When a function fails to assert the constness of its unmodified by-ref parameters, it creates headaches for everyone upstream - forcing them to either leave their own constness unstated, or engage in const-casting.

      >Const is for things like where you would do something like #define XYZ 2....
      It is also handy for declaring constants in that manner, but that's hardly it's primary use

      • (Score: 0) by Anonymous Coward on Monday August 26 2019, @04:28PM (1 child)

        by Anonymous Coward on Monday August 26 2019, @04:28PM (#885696)

        Defining arguments as const is like soldering the RAM on the motherboard. 640k enough for everybody. Pats self on back.

        • (Score: 2) by Immerman on Monday August 26 2019, @04:48PM

          by Immerman (3985) on Monday August 26 2019, @04:48PM (#885703)

          How exactly is promising not to modify the string you asked me to analyze even remotely similar to hard(ware)-limiting resource constraints?

          You expect that a function that has no need to modify its parameters is going to suddenly reach a point where it needs to do so? And more to the point, that you could change it to start modifying its parameters without causing all sorts of unexpected problems in the many places it was called in contexts that assumed it wouldn't?