views:

912

answers:

10

I have a C project where all code is organized in *.c/*.h file pairs, and I need to define a constant value in one file, which will be however also be used in other files. How should I declare and define this value?

Should it be as static const ... in the *.h file? As extern const ... in the *.h file and defined in the *.c file? In what way does it matter if the value is not a primitive datatype (int, double, etc), but a char * or a struct? (Though in my case it is a double.)

Defining stuff inside *.h files doesn't seem like a good idea generally; one should declare things in the *.h file, but define them in the *.c file. However, the extern const ... approach seems inefficient, as the compiler wouldn't be able to inline the value, it instead having to be accessed via its address all the time.

I guess the essence of this question is: Should one define static const ... values in *.h files in C, in order to use them in more that one place?

A: 

I can give you an indirect answer. In C++ (as opposed to C) const implies static. Thatis to say in C++ static const is the same thing as const. So that tells you how that C++ standards body feels about the issue i.e. all consts should be static.

fpsgamer
A: 

I'd like to see more context for your question. The type of the value is critical, but you've left it out. The meaning of the const keyword in C is quite subtle; for example const char *p; does not mean that pointer p is a constant; you can write p all you like. What you cannot write is the memory that p points to, and this stays true even as p's value changes. This is about the only case I really understand; in general, the meaning of the subtle placement of const eludes me. But this special case is extremely useful for function parameters because it extracts a promise from the function that the memory the argument points to will not be mutated.

There is one other special case everyone should know: integers. Almost always, constant, named integers should be defined in a .h file as enumeration literals. enum types not only allow you to group related constants together in a natural way, but also allow you the names of those constants to be seen in the debugger, which is a huge advantage.

I've written tens of thousands of lines of C; probably hundreds if I try to track it down. (wc ~/src/c/*.c says 85 thousand, but some of that is generated, and of course there's a lot of C code lurking elsewhere). Aside from the two cases about, I've never found much use for const. I would be pleased to learn a new, useful example.

Norman Ramsey
A: 
Gerhard
Not sure I agree with your last point. The compiler can quite easily decide that MY_MAGIC_NUMBER will never change and inline the value rather than looking it up (even in a header since preproc'er can combine H's and C to pass to compiler engine) - that's an implementation decision.
paxdiablo
Const is as much a hint to the compiler as it is to the programmer, and the compiler, when optimizing, will take full advantage of that hint. I highly doubt it would make any difference if it's a const or a define in the general case.
Sydius
Also, most modern compilers will treat a static const int very similarly to a integer literal in the code if you never take the address of the constant.
Evan Teran
+5  A: 

The rule I follow is to only declare things in H files and define them in C files. You can declare and define in a single C file, assuming it will only be used in that file.

By declaration, I mean notify the compiler of its existence but don't allocate space for it. This includes "#define"s, "typedef"s, "extern int x", and so on.

Definitions assign values to declarations and allocate space for them, such as "int x" and "const int x". This includes function definitions; including these in header files frequently lead to wasted code space.

I've seen too many junior programmers get confused when they put "const int x = 7;" in a header file and then wonder why they get a link error for x being defined more than once. I think at a bare minimum, you would need "static const int x" so as to avoid this problem.

I wouldn't be too worried about the speed of the code. The main issue with computers (in terms of speed and cost) long ago shifted from execution speed to ease of development.

paxdiablo
+1  A: 

Do you really have a need to worry about the advantage of inline? Unless you're writing embedded code, stick to readability. If it's really a magic number of something, I'd use a define; I think const is better for things like const version strings and modifying function call arguments. That said, the define in .c, declare in .h rule is definitely a fairly universally accepted convention, and I wouldn't break it just because you might save a memory lookup.

Mikeage
A: 

As a general rule, you do not define things as static in a header. If you do define static variables in a header, each file that uses the header gets its own private copy of whatever is declared static, which is the antithesis of DRY principle: don't repeat yourself.

So, you should use an alternative. For integer types, using enum (defined in a header) is very powerful; it works well with debuggers too (though the better debuggers may be able to help with #define macro values too). For non-integer types, an extern declaration (optionally qualified with const) in the header and a single definition in one C file is usually the best way to go.

Jonathan Leffler
It's not violating DRY. -You're- not repeating yourself, the compiler is repeating you. Space efficiency is not what DRY is for, look it up. -1.
rix0rrr
@rix0rr: clearly, you have a different view of the situation. However, if your headers define static objects, it is unlikely that my code will use them. There are special exceptions - but they are exceptions.
Jonathan Leffler
A: 

for autoconf environment: You can always define constants in the configure file as well. AC_DEFINE() i guess is the macro to define across the entire build.

FL4SOF
A: 

To answer the essence of your question:
You generally do NOT want to define a static variable in a header file.
This would cause you to have duplicated variables in each translation units (C files) that include the header.

variables in a header should really be declared extern since that is the implied visibility. See this question for a good explanation.

Actually, the situation might not be so dire, as the compiler would probably convert a const type to a literal value. But you might not want to rely on that behavior, especially if optimizations are turned off.

Benoit
A: 

If you need constants (real, compile time constants) you can do that three ways, putting them into header files (there is nothing bad with that):

enum {
    FOO_SIZE = 1234,
    BAR_SIZE = 5678
};

#define FOO_SIZE 1234
#define BAR_SIZE 5678

static const int FOO_SIZE = 1234;
static const int BAR_SIZE = 5678;

In C++, i tend to use the enum way, since it can be scoped into a namespace. For C, i use the macro. This basicially comes down to a matter of taste though. If you need floating point constants, you can't use the enumeration anymore. In C++ i use the last way, the static const double, in that case (note in C++ static would be redundant then; they would become static automatically since they are const). In C, i would keep using the macros.

It's a myth that using the third method will slow down your program in any way. I just prefer the enumeration since the values you get are rvalues - you can't get their address, which i regard as an added safety. In addition, there is much less boiler-plate code written. The eye is concentrated on the constants.

Johannes Schaub - litb
A: 

You should always use

const int SOME_CONST = 17;

for constants and never

#define SOME_CONST 17

Defines will almost always come back and bite you later. Consts are in the language, and are strongly typed, so you won't get weird errors because of some hidden interaction. I would put the const in the appropriate header file. As long as it's #pragma once (or #ifndef x / #define x / #endif), you won't ever get any compile errors.

FryGuy