C/C++ C/C++ question, const versus #define for defining array.

  • Thread starter Thread starter uart
  • Start date Start date
  • Tags Tags
    Array
AI Thread Summary
Using `const` for array sizes in C can lead to compilation issues, as it is not recognized as a compile-time constant in standard C, while it works in C++. The error "variable-sized type declared outside of any function" indicates that `const` cannot be used for global array sizes in C. In contrast, `#define` is treated as a preprocessor directive, allowing it to be used for array sizes without such restrictions. The discussion highlights that for C, using `enum` for defining constants is often a better practice, as it is recognized as a compile-time constant in both C and C++. Overall, the choice between `#define`, `const`, and `enum` depends on the specific use case and scope requirements.
uart
Science Advisor
Messages
2,797
Reaction score
21
I know that it's often considered better practice to use C's "typed constants" instead of "#define" as it may offer better error/type checking. I'm wondering however what happens if a const is used to declare the size of an array. For example consider the two possible methods below.

Code:
#define ListSize 80
typdef int List[ListSize];


Code:
const int ListSize = 80;
typdef int List[ListSize];

The latter doesn't compile in standard C as it doesn't seem to recognize ListSize as a compile-time constant. It does however compile ok in c++, but I'm wondering if it does actually allocate the size specified (80 in this case) right there at compile time?

Does anyone know the nitty gritty on this?

Thanks. :smile:
 
Last edited:
Technology news on Phys.org
Don't see how it could make any difference, since at compile time (ASSUMING that the compiler implementation retains the constant in time to use it in the same compiler pass) the statement

typdef int List[ListSize];

is the same (in your example) as

typedef int List[80];

As to your specific question, "compile time" is a bit more complicated than you seem to imply but in any case, NOTHING is actually allocated at compile time. It's put into an object file and the object file is loaded at load time and THEN some things get allocated.

If your questions is does the memory get allocate at load time or at run time, then it may depend on where the statement is (main module vs sub-module) but I think in general it gets allocated at run time as part of memory management.
 
Sorry I worded that badly. Yes I know that the memory doesn't get allocated at compile time, what I meant is whether it would be literally using "ListSize" as a constant (80 in this case) at compile time or if it was producing code to dynamically allocate the array based on an inquiry to the value of "ListSize" at load/run time.

It didn't really think it was the latter, but I'm confused about why the code with the "const int ..." statement doesn't compile in standard C (it does however compile in c++). The error it gives in standard C is "variable-sized type declared outside of any function".
 
uart said:
It didn't really think it was the latter, but I'm confused about why the code with the "const int ..." statement doesn't compile in standard C (it does however compile in c++).
My guess is in the case of the C++ compiler, in the compile time symbol table, it's treats the const int ListSize also as a define, while the C compiler doesn't treat it as a define.

In terms of allocation at compile time versus run time, it depends on what the operating system's loader is capable of when loading a program. For most operating systems, a typical program includes these sections: code, data, stack, with data separated into initialized data, zeroed data (statics in c), and unitialized data. The loader may be unaware of zeroed data, but the program will contain initialization code to zero out that part of the data section. The zeroed and unitialized data just have size information in a typcial program image (I think a MSDOS type .com program contains everything in one large chunk).
 
Here's an interesting little twist to this. The error message "variable-sized type declared outside of any function" seems to imply that it wouldn't be a problem if it was inside a function, but as you know error messages are not always that descriptive.

Well I decided to just test this anyway, and used the "const" to define an array inside the main program and it did actually work correctly.

So in the program preamble (before the code main or any other functions) the code
Code:
const int ListSize = 80;
typdef int List[ListSize];
wont compile in standard C.

However if I scrap the typedef (but leave the const defined there) and then place the following in the main program,
Code:
const int ListSize = 80;
...
int main(void) {
  int myList[ListSize];
  ...
then curiously it does compile without any issue.

I think I'll just have to put this down to a quirk in C and move on. :smile:
 
actually, "quirk" may not be quite right in this case as I think it's a specific design decision to require that typedefs NOT have external references. That is, a typedeff has to be self-contained because it is going to just REPLACE code elsewhere and allowing it to have external reference opens up a can of worms for OTHER errors. A #define is NOT taken as an external reference because it is immediately replace by the compiler as the typedef is being stored away to be used to replace code later.
 
uart said:
The latter doesn't compile in standard C as it doesn't seem to recognize ListSize as a compile-time constant.
Try making it static. Also, are you compiling to the C99 standard, or the older one?
 
Hurkyl said:
Try making it static. Also, are you compiling to the C99 standard, or the older one?

I tried making it static but it didn't change the error.
Unfortunately I don't know if this is C99 or older. I'm using Dev-C++ and the version of "gcc" in its bin directory is 3.4.2

This is not terribly important, I really don't have a problem using #define here. I was just helping my nephew with a trivial C program, basically showing him how to tidy it up by defining types and constant etc. I noticed that he's supposed to be writing it in standard C only but he had the file named ###.cpp. I renamed it to ###.c and the compiler immediately came up with a few errors where some c++ only code had been used. These were all easily fixed but the one with the const just bothered me a bit as to why it had that behavior.

BTW. I've just found a good link on stackoverflow where exactly this topic has been discussed. They seem to have come to the same conclusion as here.

To the question
Which one is better to use among the below statements in c:
static const int var=5;
or
#define var 5

I thought this response was good and very thorough.
It depends on what you need the value for. You (and everyone else so far) omitted the third alternative:

(1) static const int var = 5;
(2) #define var 5
(3) enum { var = 5 };

Ignoring issues about the choice of name, then:

- If you need to pass a pointer around, you must use (1).

- Since (2) is apparently an option, you don't need to pass pointers around.

- Both (1) and (3) have a symbol in the debugger's symbol table - that makes debugging easier. It is more likely that (2) will not have a symbol, leaving you wondering what it is.

- (1) cannot be used as a dimension for arrays at global scope; both (2) and (3) can.

- (1) cannot be used as a dimension for static arrays at function scope; both (2) and (3) can.

- Under C99, all of these can be used for local arrays. Technically, using (1) would imply the use of a VLA (variable-length array), though the dimension referenced by 'var' would of course be fixed at size 5.

- (1) cannot be used in places like switch statements; both (2) and (3) can.

- (2) can change code that you didn't want changed because it is used by the preprocessor; both (1) and (3) will not have unexpected side-effects like that.

- You can detect whether (2) has been set in the preprocessor; neither (1) nor (3) allows that.

So, in most contexts, prefer the 'enum' over the alternatives. Otherwise, the first and last bullet points are likely to be the controlling factors - and you have to think harder if you need to satisfy both at once.

If you were asking about C++, then you'd use option (1) - the static const - every time.

Ref : http://stackoverflow.com/questions/1674032/static-const-vs-define-in-c
 
Last edited:
uart said:
I tried making it static but it didn't change the error.
Unfortunately I don't know if this is C99 or older. I'm using Dev-C++ and the version of "gcc" in its bin directory is 3.4.2
:bugeye: That is an old version of gcc. You can get something a bit more modern that is still free.

Anyhow, the problem here is that 'const' doesn't quite mean 'const' in C. So as far as C is concerned, this is a variable-length array, and variable length arrays are only valid as local variables (i.e., some function's internal variable). You can't use variable length arrays at file scope or as an element of a structure.

BTW. I've just found a good link on stackoverflow where exactly this topic has been discussed. They seem to have come to the same conclusion as here.

I thought this response was good and very thorough.
That answer provides one key alternative to a const int or a #defined value: Use an enum value to size your arrays. This is a compile-time constant to both C and C++.

As far as sizing an array, a "static const int" is not the way to go in C++ unless the array itself has static scope. If the array has extern scope, the array size had also better have extern scope.
 
Last edited:
  • #10
D H said:
As far as sizing an array, a "static const int" is not the way to go in C++ unless the array itself has static scope. If the array has extern scope, the array size had also better have extern scope.
Eh?

Oh, I think I have an idea what you might mean, but it could only be a worry in certain cases. e.g. the following would be just fine, even preferred:

Code:
// myheader.hh
static const size_t my_array_size = 32;
extern int my_array[my_array_size];

// mysource.cc
#include "myheader.hh"

int my_array[my_array_size];
 
  • #11
uart said:
I tried making it static but it didn't change the error.
Oh well. Alas I don't have a convenient C compiler on this computer so I couldn't check myself.


I hadn't realized that particular difference between enum and static const int; interesting.
 

Similar threads

Replies
31
Views
3K
Replies
23
Views
2K
Replies
3
Views
2K
Replies
12
Views
2K
Replies
8
Views
8K
Replies
10
Views
7K
Replies
13
Views
2K
Back
Top