55

At a job interview I was asked the question "In C++ how do you access a variable faster, though the normal variable identifier or though a pointer". I must say I did not have a good technical answer to the question so I took a wild guess.

I said that access time will probably be that same as normal variable/identifier is a pointer to the memory address where the value is stored, just like a pointer. In other words, that in terms of speed they both have the same performance, and that pointers are only different because we can specify the memory address we want them to point to.

The interviewer did not seem very convinced/satisfied with my answer (although he did not say anything, just carried on asking something else), therefore I though to come and ask SO'ers wether my answer was accurate, and if not why (from a theory and technical POV).

Jerry
  • 789
  • 1
  • 6
  • 10
  • 5
    I can't really see the point of the interviewer's question. – Mike Dunlavey Aug 02 '11 at 23:29
  • 3
    @Mike: while I agree actually knowing the answer is not that useful, the answer is something you will eventually be exposed to if you have a lot of experience, along with tons of trivia stuff like cases of undefined behavior that you'll probably never encounter in your normal life, etc. The question is then arguably useful to find out if 1) The applicant has a lot of experience 2) The applicant hangs with the "cool people" such as here on stack overflow or on #c++ on freenode where this kind of "trivia" comes up all the time – Andreas Bonini Aug 03 '11 at 01:30
  • The question is useful to see if the candidate knows what is going on under the hood. This doesn't require lots of experience, just some knowledge of how the underlying hardware works. See my comment below about why I think this matters. And Andreas: I currently have the great joy of cleaning up after some programmers who didn't care about undefined behavior. That's why the code they left behind suddenly crashes when you make an unrelated change, such as changing what was in the memory they were accidentally overwriting. If you think that's trivia... – dewtell Aug 03 '11 at 07:06
  • @dewtell: I was talking about the more exotic cases of undefined behavior =) – Andreas Bonini Aug 03 '11 at 10:23
  • **Skip** to answer below at https://stackoverflow.com/a/6921440/632951 – Pacerier Jun 05 '17 at 00:05
  • @MikeDunlavey, Here you go: "[*reading data from and storing data into memory slows down the processor*...](http://archive.is/uK9Ds#selection-1005.123-1023.85)" – Pacerier Jun 05 '17 at 05:58

10 Answers10

50

When you access a "variable", you look up the address, and then fetch the value.

Remember - a pointer IS a variable. So actually, you:

a) look up the address (of the pointer variable),

b) fetch the value (the address stored at that variable)

... and then ...

c) fetch the value at the address pointed to.

So yes, accessing via "pointer" (rather than directly) DOES involve (a bit) of extra work and (slightly) longer time.

Exactly the same thing occurs whether or not it's a pointer variable (C or C++) or a reference variable (C++ only).

But the difference is enormously small.

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • 9
    Except when it's huge, eg during a load-hit-store hazard. – Crashworks Aug 02 '11 at 22:37
  • 7
    I don't see why you say that the difference is small. If it's twice as many memory accesses, then it may take twice as long. – Brent Bradburn Aug 02 '11 at 23:15
  • The difference is small because the originating speed is small. 2x0.0000001 is 0.0000002. Still a small number right? Depends on context but all but the most realtime systems probably couldn't care less about access times in these scenarios. There are scenarios where this little tiny gap matters but the OPs question lacks enough info to determine whether it really matters. – Rig Aug 03 '11 at 03:53
  • 3
    I don't think we can assume 'variables' have directly accessible memory address, especially non-local variables. – 9dan Aug 03 '11 at 04:30
  • 4
    It can be more than twice as long - see my answer below about memory hierarchy effects. And Rig, you're right that the difference for a single variable access will usually be trivial, but put enough grains of sand together and you can get a beach. E.g., if you create a frequently-accessed data structure that requires several extra levels of indirection because you didn't understand the issue, all of a sudden the difference may not look so small. The point was "does the candidate understand the underlying issue," not "what should we do in this particular case." – dewtell Aug 03 '11 at 07:17
  • 3
    Pointers are not always variables. For example, `&var` and `this` are pointers that are not variables. – fredoverflow Aug 03 '11 at 09:02
  • Let me also point out that the difference need not be "enourmously small". For example, in Objective-C, the messenger function sends billions of messages per second - and that really matters for the user whether the UI lags or works smoothly. –  Oct 06 '12 at 16:40
  • @user529758, So when you say "billion", is "billion" supposed to be big or small? With 3 lines I can create a loop that does a trillion operations. Change that to 1 line and a zillion. – Pacerier Jun 04 '17 at 23:57
  • From benchmark differences I did with both methods (with very long loops), the difference is pretty small but still exists. Accessing pointer takes 5% longer than variable. – Izik Sep 05 '18 at 11:43
  • @Izik Perhaps the CPU remembers the value the pointer is pointing at and remembers that value hasn't changed, and isn't continuously fetching each time. A better test might involve 1000+ different variables that the CPU doesn't optimize for. – user3015682 Mar 22 '20 at 21:38
39

A variable does not have to live in main memory. Depending on the circumstances, the compiler can store it in a register for all or part of its life, and accessing a register is much faster than accessing RAM.

LaC
  • 12,624
  • 5
  • 39
  • 38
  • 3
    If you want to claim that variables are "faster" then mentioning compiler optimization is not the right justification. – littleadv Aug 02 '11 at 22:25
  • 4
    @littleadv: Disagree, the speed benifits of register assignment is significant to the point of being *central* to the purpose of regular (pre c++0x `auto` allocation) local variables. – SingleNegationElimination Aug 02 '11 at 22:29
  • 1
    @Token - then you can go on and discuss temporary data caching etc. It's endless and irrelevant. The question as quoted shows that the interviewer is dumb, any answer other than the OP's would score negative points for me because it would show tendency of premature optimization. Do what makes code readable and maintainable, don't try to jump through endless hoops to save on *potential* compiler optimization. – littleadv Aug 02 '11 at 22:44
  • 4
    Allocating variables is not really an optimization, it's a necessary part of compilation. If you define "int a" within a function, you're not saying "there's a location in RAM called 'a'", and then the compiler goes and optimizes it by putting it into a register instead. What you're saying is "there's an integer variable called a", and the compiler has to decide where to put it. – LaC Aug 02 '11 at 22:50
  • @LaC - *the compiler has to decide where to put it.* - precisely. Assuming it will be in the register is plain wrong. – littleadv Aug 02 '11 at 22:52
  • @littleadv: you are actually telling the compiler your _intent_: lesson to learn: don't go the indirect route and tell the compiler what you actually want. – ninjalj Aug 02 '11 at 23:00
  • 11
    @littleadv, reread my answer: it was an example, not an assumption. The problem is that Jerry thought that an *identifier is a pointer to the memory address where the value is stored*, while it is not. In fact, there may not be a memory address at all. – LaC Aug 02 '11 at 23:34
  • 2
    According to my information, pointer will never be stored in a register, only if a variable is used a lot it will be saved and if a pointer is going to be saved in a register then it's value not the value of the variable pointed to, I am taking compiler course that's really what is being done. – Ahmed Jolani May 05 '12 at 16:55
  • 1
    "Any answer other than the OP's would score negative points"? Then, littleadv, you obviously do not understand how this language works or, indeed, how computers work at all. I think paulsm4's answer is superior to this one for being definitive and specific, but I'd give at least half credit to LaC for giving a "reasonable situation" in which the pointer will be obviously slower. In contrast, the local variable can literally just never be slower. Someone who claimed that is the only one I would give negative credit to. OP's answer I would give 0 credit. – codetaku May 12 '15 at 20:25
33

Let's ignore optimization for a moment, and just think about what the abstract machine has to do to reference a local variable vs. a variable through a (local) pointer. If we have local variables declared as:

int i;
int *p;

when we reference the value of i, the unoptimized code has to go get the value that is (say) at 12 past the current stack pointer and load it into a register so we can work with it. Whereas when we reference *p, the same unoptimized code has to go get the value of p from 16 past the current stack pointer, load it into a register, and then go get the value that the register points to and load it into another register so we can work with it as before. The first part of the work is the same, but the pointer access conceptually involves an additional step that needs to be done before we can work with the value.

That was, I think, the point of the interview question - to see if you understood the fundamental difference between the two types of access. You were thinking that the local variable access involved a kind of lookup, and it does - but the pointer access involves that very same type of lookup to get to the value of the pointer before we can start to go after the thing it is pointing to. In simple, unoptimized terms, the pointer access is going to be slower because of that extra step.

Now with optimization, it may happen that the two times are very close or identical. It is true that if other recent code has already used the value of p to reference another value, you may already find p in a register, so that the lookup of *p via p takes the same time as the lookup of i via the stack pointer. By the same token, though, if you have recently used the value of i, you may already find it in a register. And while the same might be true of the value of *p, the optimizer can only reuse its value from the register if it is sure that p hasn't changed in the mean time. It has no such problem reusing the value of i. In short, while accessing both values may take the same time under optimization, accessing the local variable will almost never be slower (except in really pathological cases), and may very well be faster. That makes it the correct answer to the interviewer's question.

In the presence of memory hierarchies, the difference in time may get even more pronounced. Local variables are going to be located near each other on the stack, which means that you are very likely to find the address you need already in main memory and in the cache the first time you access it (unless it is the very first local variable you access in this routine). There is no such guarantee with the address the pointer points to. Unless it was recently accessed, you may need to wait for a cache miss, or even a page fault, to access the pointed-to address, which could make it slower by orders of magnitude vs. the local variable. No, that won't happen all the time - but it's a potential factor that could make a difference in some cases, and that too is something that could be brought up by a candidate in response to such a question.

Now what about the question other commenters have raised: how much does it matter? It's true, for a single access, the difference is going to be tiny in absolute terms, like a grain of sand. But you put enough grains of sand together and you get a beach. And though (to continue the metaphor) if you are looking for someone who can run quickly down a beach road, you don't want someone who will obsess about sweeping every grain of sand off the road before he or she can start running, you do want someone who will be aware when he or she is running through knee-deep dunes unnecessarily. Profilers won't always rescue you here - in these metaphorical terms, they are much better at recognizing a single big rock that you need to run around than noticing lots of little grains of sand that are bogging you down. So I would want people on my team who understand these issues at a fundamental level, even if they rarely go out of their way to use that knowledge. Don't stop writing clear code in the quest for microoptimization, but be aware of the kinds of things that can cost performance, especially when designing your data structures, and have a sense of whether you are getting good value for the price you are paying. That's why I think this was a reasonable interview question, to explore the candidate's understanding of these issues.

dewtell
  • 1,402
  • 10
  • 14
27

What paulsm4 and LaC said + a little asm:

    int y = 0;
mov         dword ptr [y],0  
    y = x;
mov         eax,dword ptr [x]   ; Fetch x to register
mov         dword ptr [y],eax   ; Store it to y
    y = *px;
mov         eax,dword ptr [px]  ; Fetch address of x 
mov         ecx,dword ptr [eax] ; Fetch x 
mov         dword ptr [y],ecx   ; Store it to y

Not that on the other hand it matters much, also this probably is harder to optimize (fe. you can't keep the value in cpu register, as the pointer just points to some place in memory). So optimized code for y = x; could look like this:

mov dword ptr [y], ebx - if we assume that local var x was stored in ebx

Marcin Deptuła
  • 11,789
  • 2
  • 33
  • 41
4

I think the interviewer was looking for you to mention the word register. As in, if you declare a variable as a register variable the compiler will do its utmost to ensure that it is stored in a register on the CPU.

A bit of chat around bus access and negotiation for other types of variables and pointers alike would have helped to frame it.

Alex Barrett
  • 16,175
  • 3
  • 52
  • 51
Adrian Regan
  • 2,240
  • 13
  • 11
  • 4
    I would expect a modern compiler to ignore you, and decide for itself which variables should be in registers at every moment (well, it will ignore you unless you take the address of such a variable). – ninjalj Aug 02 '11 at 22:43
3

paulsm4 and LaC has already explained it nicely along with other members. I want to emphasize effect of paging when the pointer is pointing to something in heap which has been paged out.

=> Local variables are available either in the stack or in the register
=> while in case of pointer, the pointer may be pointing to an address which is not in cache and paging will certainly slow down the speed.

Abhinav
  • 1,496
  • 3
  • 15
  • 31
  • Is there nobody interested in the paging related issues? – Abhinav Oct 05 '11 at 09:49
  • 2
    Sure - I already addressed this issue in my answer above (starting with "In the presence of memory hierarchies..."). It's not just paging, it affects cache-related accesses too. But I think it's an additional issue in addition to the main point that the interviewer was looking for. – dewtell Feb 06 '13 at 20:56
2

A variable holds a value of certain type, and accessing the variable means getting this value, from memory or from a register. When getting the value from memory we need to get it's address from somewhere - most of the time it has to be loaded into a register (sometimes it can be part of the load command itself, but this is quite rare).

A pointer keeps an address of a value; this value has to be in memory, the pointer itself can be in memory or in a register.

I would expect that on average access via a pointer will be slower than accessing the value through a variable.

MaximG
  • 104
  • 7
2

Your analysis ignores the common scenario in which the pointer itself is a memory variable which must also be accessed.

There are many factors that affect the performance of software, but if you make certain simplifying assumptions about the variables involved (notably that they are not cached in any way), then each level of pointer indirection requires an additional memory access.

int a = 1234; // luggage combination
int *b = &a;
int **c = &b;
...
int e = a; // one memory access
int e = *b; // two memory accesses
int e = **c; // three memory accesses

So the short answer to "which is faster" is: ignoring compiler and processor optimizations which might be occurring, it is faster to access the variable directly.

In a best-case scenario, where this code is executed repeatedly in a tight loop, the pointer value would likely be cached into a CPU register or at worst into the processor's L1 cache. In such a case, it is likely that a first-level pointer indirection is as fast or faster than accessing the variable directly since "directly" probably means via the "stack pointer" register (plus some offset). In both cases you are using a CPU register as a pointer to the value.

There are other scenarios that could affect this analysis, such as for global or static data where the variable's address is hard-coded into the instruction stream. In such a scenario, the answer may depend on the specifics of the processor involved.

Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • However, it seems like the interview question is suspect. Why would you use a pointer if you *could* access the variable directly? I think code clarity will dictate your choice -- not performance. – Brent Bradburn Aug 02 '11 at 23:40
  • Along those same lines, accessing a value via a pointer assures that the value won't be cached in a register (as hinted at by @LaC), although it can still be optimized in the cache. In the general case you want to avoid the use of pointers for many reasons. – Brent Bradburn Aug 02 '11 at 23:42
2

I think the key part of the question is "access a variable". To me, if a variable is in scope, why would you create a pointer to it (or a reference) to access it? Using a pointer or a reference would only make sense if the variable was in itself a data structure of some sort or if you were acessing it in some non-standard way (like interpreting an int as a float).

Using a pointer or a reference would be faster only in very specific circumstances. Under general circumstances, it seems to me that you would be trying to second guess the compiler as far as optimization is concerned and my experience tells me that unless you know what you're doing, that's a bad idea.

It would even depend on the keyword. A const keyword might very well mean that the variable is totally optimized out at compile time. That is faster than a pointer. The register keyword does not guarantee that the variable is stored in a register. So how do you know whether its faster or not? I think the answer is that it depends because there is no one size fits all answer.

Community
  • 1
  • 1
Carl
  • 43,122
  • 10
  • 80
  • 104
  • What if you have an array, and within a loop that iterates that array you need to access the content of each item many times. Would making a pointer to that item early in the loop impact performance? Is looking up a pointer reference faster or slower than accessing an array entry? – thomthom Mar 12 '12 at 11:15
  • @thomthom: There is only one way to find out with that and that is to try it on your compiler and platform of choice. You might be surprised with the results :) – Carl Mar 12 '12 at 20:20
1

I think a better answer might be it depends on where the pointer is 'pointing to'. Note, a variable might already be in the cache. However a pointer might incur a fetch penalty. It's similar to a linked list vs Vector performance tradeoff. A Vector is cache friendly because all of your memory is contigious. However a linked list, since it contains pointers, might incur a cache penalty because the memory is potentially scattered all over the place