I am fairly new to C and I don't understand why the following two statements do not create the same result:
char *fields[14] = {NULL};
const int num_fields = 14;
char *fields[num_fields] = {NULL};
Option 1 works, but option 2 does not. It says "variable-sized object may not be initialized" and it gives a warning "warning: excess elements in array initializer". I use gcc 4.2.1 on OSX.
Thanks for sharing your thoughts!
The second object is called a VLA (Variable Length Array), well defined by C99. To achieve what you want you can use this:
for (i = 0; i < num_fields; i++)
fields[i] = NULL;
The gist of the issue is that const int num_fields is very different from 14, it's not a constant, it's read-only.
Even if you define num_fields with const keyword, compiler interprets it as variable only. you can have alternative for this by defining following macro:
#define num_fields 14
char *fields[num_fields] = {NULL};
Although num_fields has a const qualifier, it is still considered a variable by the compiler.
Therefore, you are attempting to declare a variable-sized array, and initialisers (the {NULL} part) cannot be used in conjunction with them.
Your construction works in C++, where a const int will be treated as a compile-time constant ("constant expression"), and hence available for use as a compile-time array size.
(This aspect was one of B. Stroustrup's design goals for C++, to eliminate the need for compile-time macros if possible)
However in C, your definition of "num_fields" effectively declares a read-only memory location with your preset value, and hence is not under C rules a "constant expression" valid at compile time, and hence may not be used as an array size at the outermost 'program' scope.
Related
Can I force GCC to throw a warning or error at compile-time if the number of elements in a certain explicitly-initialized C array is not equal to a certain value?
Consider the following simple C program:
#include <stdio.h>
enum my_enum {
MY_ENUM_FIRST,
MY_ENUM_SECOND,
MY_ENUM_THIRD,
MY_ENUM_COUNT
};
// indexable by my_enum
const char *my_enum_names[] = {
"first",
"second",
"third",
};
int main(void) {
int i;
for (i = 0; i < MY_ENUM_COUNT; i++)
{
printf("%s\n", my_enum_names[i]);
}
}
Unless they are directly adjacent in the code, a developer might not realize that the enum and array must be kept "synchronized" with each other. A developer may add an entry to the enum but not to the array (or vice-versa) and therefore expose an out-of-bounds vulnerability.
Can I add some sort of pragma or attribute to the definition of my_enum_names so that if its size is not equal to MY_ENUM_COUNT, the compiler will throw a warning or error?
Some clarifications:
I am referring specifically to arrays which are explicitly initialized, meaning their size is known at compile-time.
I am referring specifically to the GCC compiler, including compiler extensions.
I swear I've done this before, possibly using one of GCC's __attribute__ extensions, but now I can't find any documentation on any feature that does what I want.
_Static_assert(sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT,
"my_enum_names is the wrong size.");
Prior to the addition of _Static_assert to the language, you could force errors in these situations with declarations such as:
extern char my_enum_namesIsTheWrongSize[1];
extern char my_enum_namesIsTheWrongSize[sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT];
If the test in the latter were false, it would attempt to declare an array with zero elements, which is an error itself, but, just in case the compiler does not report zero-size arrays, also conflicts with the preceding declaration, and so it should generate an error message.
How about
const char *my_enum_names[MY_ENUM_COUNT] = { ... };
Then the array will always contain enough elements, but some may be NULL which you then need to add check for instead. It's still better than risking going out of bounds.
Also, with the above, if you remove enumerations then the compiler will warn you about to many initializers if you forget to update the array initialization.
Hey I'm working on a problem and here is what I have to do:-
Write a function called initarray that takes an array of pointers to int and an int representing the size of the array, as arguments. The function should initialize the array with pointers to ints (use malloc) that have a value corresponding to the array indices at which a pointer to them are stored (the pointer stored at array index 2 should point to an integer with a value of 2).
So far I've written this, but It's giving me an error "[Error] variable-sized object may not be initialized"
Can you tell me what I'm doing wrong here?
#include<stdio.h>
void initArray(int **a, int sz){
int i;
for (i = 0; i < sz; i++) {
a[i] = calloc (1, sizeof **a);
*a[i] = i;
}
}
int main(){
const int Var = 10;
int *array[Var] = {NULL};
initArray(array,3);
}
For historical reasons, the value of a const variable is never considered a constant expression in C.
So if you use it as an array dimension, then the array is a variable-length array, and variable-length arrays are not allowed to have initializers.
One solution not mentioned yet is to use enum. Enumerators are in fact constant expressions, and they don't suffer from the same "bigger hammer" issue as preprocessor macros:
int main()
{
enum { Var = 10 };
int *array[Var] = {NULL};
initArray(array,3);
}
C has no symbolic constants with user-defined type. You encountered one of the differences to C++.
The const qualifier just is a guarantee you give to the compiler you will not change the variable(!) Var.
Arrays with initialiser and global arrays require a constant expressing which can be evaluated at compile-time. As Var is semantically still a variable, you cannot use it.
The C-way to emulate symbolic constants are macros:
#define ARRAY_SIZE 10
...
// in your function:
int *array[ARRAY_SIZE] = ...
Macros are handled by the preprocessor and are a textual replacement before the actual compiler sees the code.
Note I changed the name to a more self-explanatory one. The macro should also be at the file-level, typically near the beginning to allow easier modifications. Using the integer constant 10 directly in the code is a bad idea. Such magic numbers are often cause of errors when a modification is required.
The error would suggest that you can't use an initializer (the = {NULL} in your main function) on a variable-sized object. While it looks like it isn't variable (because of the const on Var, and because 10 is a constant) it sees it as variable because you're accessing it through a variable. If you use:
int *array[10] = {NULL}
I think your snippet will work fine.
I am creating an array on stack as
static const int size = 10;
void foo() {
..
int array[size];
..
}
However, I get the compile error: "expression must have a constant value", even though size is a constant. I can use the macro
#define SIZE (10)
But I am wondering why size marked const causes compilation error.
In C language keyword const has nothing to do with constants. In C language, by definition the term "constant" refers to literal values and enum constants. This is what you have to use if you really need a constant: either use a literal value (define a macro to give your constant a name), or use a enum constant.
(Read here for more details: Shall I prefer constants over defines?)
Also, in C99 and later versions of the language it possible to use non-constant values as array sizes for local arrays. That means that your code should compile in modern C even though your size is not a constant. But you are apparently using an older compiler, so in your case
#define SIZE 10
is the right way to go.
The answer is in another stackoverflow question, HERE
it's because In C objects declared with the const modifier aren't true
constants. A better name for const would probably be readonly - what
it really means is that the compiler won't let you change it. And you
need true constants to initialize objects with static storage (I
suspect regs_to_read is global).
if you are on C99 your IDE compiler option may have a thing called variable-length array (VLA) enable it and you won't get compile error, efficiently without stressing your code though is with MALLOC or CALLOC.
static const int size = 10;
void foo() {
int* array;
array = (int *)malloc(size * sizeof(int));
}
static const int LOG_MAX = 31;
static int log_table[LOG_MAX];
This code is inside of a function in C. When I try to compile I get the error:
"main.c:19:16: error: storage size of 'log_table' isn't constant".
I don't understand this since LOG_MAX is const.
Just to clarify this is C code and I am using GCC.
In older C and C++ standards, the array bounds of an array had to be a constant literal evaluated at compile time. A const variable isn't necessary evaluated at compile time, it could be created in runtime as a local variable. Also, as pointed out in another answer, const should actually be regarded read-only rather than anything else.
In all C and C++ standards, static arrays must always have their size set using a constant literal. (Or to be picky, this applies to any variable with static storage duration)
In newer C standards (C99, C11) however, the code you posted is perfectly fine if you leave out the static keyword. It will then create a variable-length array (VLA), which may or may not be what you wanted to do.
I'm not sure about the latest C++11 standard, but as far as I know it does not support VLAs.
const does not mean constant in C but rather read-only. LOG_MAX is not a constant in your program.
Here are two ways to have a constant:
#define LOG_MAX 31
or
enum {
LOG_MAX = 31
};
This isn't valid C, even though the int is const and static.
I would recommend doing something like
#define LOG_MAX 31
static int log_table[LOG_MAX];
This fails since a const int variable is not considered a compile-time constant in C.
But since the array is going to be static, you can be sure that the "full" declaration is always available, i.e. it's never going to be referenced through a pointer. Thus, you can inline the size and use sizeof in all places where you wanted to use LOG_MAX:
static int log_table[32];
and then elsewhere in the same function:
const size_t log_max = sizeof log_table / sizeof *log_table;
This keeps the "magic constant" around, but only in one place and its purpose should be pretty clear given the way the log_table is used. This is all inside a single function, after all, it's not scary global data.
You should use the preprocessor :
#define LOG_MAX 31
static int log_table[LOG_MAX];
const int size = 10; // realna ilość danych
int tablica[size+1];
i have:
variable-size type declared outside of any function
Use
#define size 10
instead of a const int. The latter is not a compile-time constant in C, but a variable that cannot be assigned to (unless via a pointer and a cast to get rid of const).
(This is a difference between C and C++.)
You could use an enum.
enum
{
size = 10
};
int table[size + 1];
Use:
enum { size = 10 };
This is a constant value that can be used in declarations and in case labels and so on. In C99, inside a function, the original code would not be a problem -- your array tablica would be a VLA or variable-length array (and the compiler error message is trying to say "you can't have a VLA outside a function").
Using an enum gives better traceability when you use a debugger on your code; the symbol is included in the symbol table. Typically, C preprocessor symbols are not available to the debugger, so trying to print 'size' when it is #define'd doesn't print an answer; printing 'size' when it is an enum does.
See also: "static const" vs "#define" in C
The error is fairly self-explanatory. You can't declare a variable-length array outside of a function. Although the size of the array you're creating is, in practice, fixed at compile time, you've still technically violated the constraints of the language.
The usual choices are:
Move the array into a function. (Usually the best option, remember globals are to be avoided when possible.)
#define size n where n is the size you want, instead of using an int. (Usually better than "magic numbers", and pretty standard practice in traditional C.)
Use a "magic number" (int tablica[11];). (Usually the last choice, though sometimes it does make more sense.)