16

Can you give me a quick runthrough of what these 4 keywords are used for and why?

I understand the basics that google would tell you on register and volatile, but would like to know a little more (just a practical overview). Extern and explicit confuse me a little as I've never found a reason to have to use them myself despite doing fairly low-level embedded systems code. Again, I can google but I'd prefer a quick, practical summary from an expert so it sticks in my mind.

Paul Sonier
  • 38,903
  • 3
  • 77
  • 117
John Humphreys
  • 37,047
  • 37
  • 155
  • 255
  • 6
    Have you tried any standard C++ text book, or even Wikipedia? – Kerrek SB Jul 27 '11 at 23:39
  • 8
    `extern` is rare? – BoltClock Jul 27 '11 at 23:40
  • 2
    `explicit` certainly isn't a "rarer" keyword. I use the `explicit` keyword way more than all the other three put together. – In silico Jul 27 '11 at 23:43
  • 2
    Funny, I never used `explicit` and `register` in my life, but use `extern` a lot, and sometimes even `volatile`. – Blindy Jul 27 '11 at 23:46
  • @Blindy: [`explicit` is used to prevent implicit conversions with constructors](http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean). Constructors that allow implicit conversions are not appropriate for a lot of classes I write, so I end up using it quite often. Certainly more than `register` or `volatile`. – In silico Jul 27 '11 at 23:50
  • 3
    You left out `restrict`. – Chris Lutz Jul 27 '11 at 23:52
  • Thanks for all the input. It's always pretty ammusing to see how different people use/don't use specific language features :p I always notice it when I bring them up in the work lab, haha. – John Humphreys Jul 28 '11 at 00:55
  • register - Never used. volatile - Rarely used. explicit - Many times. extern - Umpteen times. – Ajay Jul 28 '11 at 02:21

5 Answers5

29

extern

extern is overloaded for several uses. For global variables, it means that it is declaring the variable, not defining it. This is useful for putting global variables in headers. If you put this in a header:

int someInteger;

Each .cpp file that includes that header would try to have its own someInteger. That will cause a linker error. By declaring it with extern, all you're saying is that there will be a someInteger somewhere in the code:

extern int someInteger;

Now, in a .cpp file, you can define int someInteger, so that there will be exactly one copy of it.

There is also extern "C", which is used for specifying that certain functions use C-linkage rules rather than C++. This is useful for interfacing with libraries and code compiled as C.

In C++0x, there will also be extern template declarations. These are the opposite of explicit template instantiation. When you do this:

template class std::vector<int>;

You're telling the compiler to instantiate this template right now. Normally, the instantiation is delayed until the first use of the template. In C++0x, you can say:

extern template class std::vector<int>;

This tells the compiler not to instantiate this template in this .cpp file, ever. That way, you can control where templates are instantiated. Judicious use of this can substantially improve compile times.

explicit

This is used to prevent automatic conversions of types. If you have a class ClassName with the following constructor:

ClassName(int someInteger);

This means that if you have a function that takes a ClassName, the user can call it with an int, and the conversion will be done automatically.

void SomeFunc(const ClassName &className);
SomeFunc(3);

That's legal, because ClassName has a conversion constructor that takes an integer. This is how functions that take std::string can also take a char*; std::string has a constructor that takes a char*.

However, most of the time you don't want implicit conversions like this. You only usually want conversions to be explicit. Yes, it's sometimes useful as with std::string, but you need a way to turn it off for conversions that are inappropriate. Enter explicit:

explicit ClassName(int someInteger);

This will prevent implicit conversions. You can still use SomeFunc(ClassName(3)); but SomeFunc(3) will no longer work.

BTW: if explicit is rare for you, then you're not using it nearly enough. You should use it at all times, unless you specifically want conversion. Which is not that often.

volatile

This prevents certain useful optimizations. Normally, if you have a variable, C/C++ will assume that it's contents will only change if it explicitly changes them. So if you declare a int someInteger; as a global variable, C/C++ compilers can cache the value locally and not constantly access the value every time you use it.

Sometimes, you want to stop this. In those cases, you use volatile; this prevents those optimizations.

register

This is just a hint. It tells the compiler to try to put the variable's data in a register. It's essentially unnecessary; compilers are better than you are at deciding what should and should not be a register.

Community
  • 1
  • 1
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 4
    +1 - great answer overall. Re `volatile`, "only change if it explicitly changes them": i.e. in the surrounding code/flow, and not via interrupt handlers or other threads. Separately, `volatile` also ensures that *writes* to the variable create machine-code-level writes to memory (and not just a register) - that does not necessarily mean that the CPU's core-specific cache will flush that write all the way to physical memory, so it isn't an alternative to memory barriers or locks. – Tony Delroy Jul 28 '11 at 02:43
  • One potentially legitimate case for `register`: some CPUs have larger registers than the associated memory content - for example, 80 bit floating point registers with rounding to 64 bit doubles when written to memory. Perhaps explicit use of `register` might help control when that loss of precision is performed, giving priority to a particular value such as a total despite many other values used for calculations between updates to that total...? – Tony Delroy Jul 28 '11 at 02:49
  • 1
    `register` can be useful in embedded, in cases when the exact timing between two events have to be measured in CPU cycles. For embedded compilers, the `register` keyword is usually not just a hint, but a strict command. – vsz Jan 23 '14 at 07:26
7

register used as a hint to the compiler that a variable should be stored in a register instead of on the stack. Compilers will frequently ignore this and do whatever they want; variables will be allocated into registers if at all possible anyway.

volatile indicates memory may change without the program actually doing anything. This is another hint to the compiler that it should avoid optimizing accesses to that location. For instance, if you have two consecutive writes to the same location with no intervening reads, the compiler might optimize away the first one. However, if the location you're writing to is a hardware register, you would need every write to go through, exactly as written. So volatile is like saying "just trust me on this".

extern indicates a definition occurs outside of the current file. Useful for global variables, but usually implied in a declaration anyway. As Blindy notes, it's also useful for indicating a function should have C linkage. A function with C linkage will get compiled using its actual name as its symbol in the output executable. C++ functions include more information, like the types of their arguments in their symbols. This is why overloading works in C++ but not in C.

explicit applies to C++ constructors. It means that the constructor should not be called implicitly. For example, say you have an Array class with a constructor that accepts an integer capacity. You don't want integer values being implicitly converted into Array objects just because there's an integer constructor.

Jay Conrod
  • 28,943
  • 19
  • 98
  • 110
2

register is mostly ignored these days, but it's supposed to hint to the compiler that you'd rather the variable be in a register instead of on the stack. Optimizers do such a good job these days that it's irrelevant now.

volatile tells the compiler to not assume that the value is only changed from the current thread, so it will always read the actual memory value instead of caching it between reads. It's useful for multi-threaded applications, but you're better off using OS primitives anyway (events, semaphores etc).

extern doesn't define the value, it only declares it. It's mostly used for exporting and importing functions from DLL's or shared libraries (.a). A side-effect also allows you to turn off name mangling for C++ using extern "C".

And explicit allows you to specify that a constructor has to be explicit, as opposed to implicit converting constructors (where you can write CMyClass val=10; if it has an implicit constructor that takes an int).

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • 1
    `volatile` is needed to share access with hardware, no OS primitives will help you there. – littleadv Jul 27 '11 at 23:46
  • Well I was talking about user-space programs, where the OS usually provides APIs to allow "nice" access to hardware registers. Kernel code is a different story of course. – Blindy Jul 27 '11 at 23:48
1

register is used to direct the compiler to use a register for storing this value, modern compilers optimize to use this during for-loops and the like.

volatile are varaibles that can be changed by an external process or during multithreaded application runtimes.

extern tells the linker that the variable is defined in a different file.

explicit directs the compiler not to allow implicit conversions of type.

sampwing
  • 1,238
  • 1
  • 10
  • 13
1

1: Register is used when you wish to force a value to be kept in register rather than kept in RAM. For instance you might do the following:

register int x;

This would let the compiler know that you want this int to be placed in the CPU register, which should give you faster access to it. However, your compiler is allowed to ignore this keyword in the process of optimization and most of the time good compilers will place variables in registers if they need to be anyway. It's mainly a redundant keyword in my opinion now.

2: Volatile hints to the compiler that the variable will change regularly, for instance if you define some float as volatile:

volatile float flt;

This tells the compiler that you want to perform optimization specific to regularly changing variables upon it. It also states that the variable may change without input from the active program. Again, a primarily redundant keyword now (except in multi-threaded programming).

3: Extern tells the compiler that the definition is in another file to the one the variable was declared in, for instance you may have some general header file, which you include in most of your files, here you might want to declare some global pointers, so you would do the following:

extern MyClass* g_pClassPointer;

You would then proceed to declare at the top of the cpp file your MyClass is implemented in:

MyClass* g_pClassPointer = nullptr;

The extern keyword is also used to declare to the compiler that you are using raw C code or ASM code, for instance, you could do the following:

extern __asm {
    mov eax, 2
    mov ebx, 3
    add eax, ebx
}

Or if you just wanted to use raw C code, you could use extern "C" and your compiler will recognise that.

4: Explicit is for use when you don't want implicit conversion within a constructor, for more information see this thread. It's primarily used for debugging purposes, and to ensure more stringent rules are obeyed when doing OOP.

Community
  • 1
  • 1
Thomas Russell
  • 5,870
  • 4
  • 33
  • 68
  • 2
    -1: volatile is not a "hint". It states that "these accesses must occur in the same order and the same number of times as I've asked for". It's used a lot in low-level embedded systems for talking to hardware, (as well as in multi-threaded code - but there's usually a better way of communicating than through volatiles) – Martin Thompson Jul 28 '11 at 08:22