473,836 Members | 2,240 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

const array declaration

Hi guys,

In a program (not my own) I encountered the declaration of a constant
pointer to an array consisting of two other const pointers to arrays.
Not quite sure why they do it so complicated, but is it legal? Most
compilers accept it, but one doesn't recognize the rhs as a constant.
What are the requirements for the rhs in the declaration of a const
pointer? Is the following program legal C?

int main(int argc, char *argv[]) {
const char *a[] = {"A"};
const char *b[] = {"B"};
const char **z[] = {a, b}; /* this is the statement in question */
return (0);
}

The error message is
"t.c", line 4: error: initialization: constant expression is expected
for variable: `z'

Thanks in advance,

Herbert
Nov 14 '05
16 41783
On Mon, 09 Feb 2004 19:43:36 GMT, "Tom St Denis"
<to*@securescie nce.net> wrote in comp.lang.c:

"Eric Sosman" <Er*********@su n.com> wrote in message
news:40******** *******@sun.com ...
The complaining compiler is correct: `a' and `b' are not
constant expressions.
Despite the spelling, `const' is not
"constant."


Yes it is. There is just a diff between

const char *varname;

and

char const *varname;

The former means the values in varname[...] are constant. E.g.

varname[0] = 'a';

will produce a warning.

In the latter the actual pointer "varname" is constant so

varname = &somebuf;

will produce a warning while

varname[0] = 'a';

will not.

const char const *varname;

will make both constant.

Tom


Look on the bright side, Tom. I did this once in comp.lang.c, years
ago, and had my *ss handed to me. I'll never make that particular
mistake again. I doubt you will, either.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #11
Thanks for the lengthy discussion, but it seems like the question is
still not anwered. What I've learnt from it so far is that the "const"
seems to refer to the array elements, not the pointers themselves.
However, if I add another "const" level, the error message remains the
same. For completeness, here again the original program:

int main(int argc, char *argv[]) {
const char *a[] = {"A"};
const char *b[] = {"B"};
const char **z[] = {a, b};
return (0);
}

and the modified one:

int main(int argc, char *argv[]) {
const char * const a[] = {"A"};
const char * const b[] = {"B"};
const char * const *z[] = {a, b};
return (0);
}

The error message I'm getting is
"t.c", line 4: error: initialization: constant expression is expected
for variable: `z'

Gcc with -pedantic also reports an error:
t.c:4: initializer element is not computable at load time
t.c:4: (near initialization for `z[0]')
t.c:4: initializer element is not computable at load time
t.c:4: (near initialization for `z[1]')

Again the question: is this legal C, and if not, how can it be made
legal?

TiA,

Herbert
Nov 14 '05 #12
hf******@yahoo. co.uk (herbertF) wrote:
Thanks for the lengthy discussion, but it seems like the question is
still not anwered.
Actually, it is.
What I've learnt from it so far is that the "const"
seems to refer to the array elements, not the pointers themselves.
However, if I add another "const" level, the error message remains the
same. For completeness, here again the original program:

int main(int argc, char *argv[]) {
const char *a[] = {"A"};
const char *b[] = {"B"};
What you've also learned is that, despite having the keyword "const"
somewhere in their definitions, these objects are not compile-time
constants, so...
const char **z[] = {a, b};


....they cannot be used as initialisers. No amount of const-qualifying,
whether of the pointers themselves or of their underlying types, can
change that.

Richard
Nov 14 '05 #13
> int main(int argc, char *argv[]) {
const char *a[] = {"A"};
const char *b[] = {"B"};
const char **z[] = {a, b};
return (0);
}

and the modified one:

int main(int argc, char *argv[]) {
const char * const a[] = {"A"};
const char * const b[] = {"B"};
const char * const *z[] = {a, b};
return (0);
}

The error message I'm getting is
"t.c", line 4: error: initialization: constant expression is expected
for variable: `z'

Gcc with -pedantic also reports an error:
t.c:4: initializer element is not computable at load time
t.c:4: (near initialization for `z[0]')
t.c:4: initializer element is not computable at load time
t.c:4: (near initialization for `z[1]')


Okay, this is really weird. here are the 2 programs I compiled:

(1)
int main(int argc, char **argv) {
const char *a[] = {"A"}; //constant pointer
const char *b[] = {"B"};
const char **z[] = {a, b};
return 0;
}

and (2)
int main(int argc, char **argv) {
const char *const a[] = {"A"}; //constant pointer AND constand data
const char *const b[] = {"B"};
const char *const *z[] = {a,b};
return 0;
}
-----

I compiled both with GCC 3.3.2 like
$gcc -Wall -std=c99 -pedantic const_test_1.c
$gcc -Wall -std=c99 -pedantic const_test_2.c

Only reply I got was:
const_test_1.c: In function "main":
const_test_1.c: 4: warning: unused variable `z'
(the same for the other file)

What compiler do you have? I don't see why yours complains :/
Nov 14 '05 #14
I think I found the answer myself. Could somebody comment if my
conclusions are correct? Here are the relevant paragraphs from the
(draft) C99 standard:

6.2.4 Storage duration of objects, paragraph 4:
For such an object that does not have a variable length array type,
storage is guaranteed to be reserved for a new instance of the object
on each entry into the block with which it is associated; the initial
value of the object is indeterminate. If an initialization is
specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes
indeterminate each time the declaration is reached. Storage for the
object is no longer guaranteed to be reserved when execution of the
block ends in any way. (Entering an enclosed block or calling a
function suspends, but does not end, execution of the current block.)

6.6, paragraph 2:

A constant expression can be evaluated during translation rather than
runtime, and accordingly may be used in any place that a constant may
be.

Paragraph 10:

An implementation may accept other forms of constant expressions.

6.7.8 Initialization, paragraph 1:
Syntax
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier

The conclusion is that, because a and b are not static, their
addresses are not known at compile or load time (and may change
between calls to the routine in question), so they are not allowed in
the "designator " part of an initialisation expression, which has to be
a constant expression. Compilers who think they know enough may allow
it (6.6, paragraph 10). To make it fully portable, the static
qualifier has to be present for a and b (in addition to const).

Is this correct?

Btw., I found this about the much discussed question of where in the
line "const" goes:

6.7.3 Type qualifiers, paragraph 8:

If the specification of an array type includes any type qualifiers,
the element type is so qualified, not the array type. If the
specification of a function type includes any type qualifiers, the
behavior is undefined.

H.
Nov 14 '05 #15
herbertF <hf******@yahoo .co.uk> wrote:
Thanks for the lengthy discussion, but it seems like the question is
still not anwered. What I've learnt from it so far is that the "const"
seems to refer to the array elements, not the pointers themselves.
However, if I add another "const" level, the error message remains the
same. For completeness, here again the original program: int main(int argc, char *argv[]) {
const char *a[] = {"A"};
const char *b[] = {"B"};
const char **z[] = {a, b};
return (0);
} and the modified one: int main(int argc, char *argv[]) {
const char * const a[] = {"A"};
const char * const b[] = {"B"};
const char * const *z[] = {a, b};
return (0);
} The error message I'm getting is
"t.c", line 4: error: initialization: constant expression is expected
for variable: `z'


What you failed to learn, however, is that const-qualifying a
variable does not make it a constant, it simply makes it
read-only.

Here is an example:

const int x = 2; /* x is read-only, value is 2 */

int array1[] = {1}; /* 1 is an integer constant, okay */
int array2[] = {x}; /* x is not a constant, not okay! */

Furthermore:

x = 5; /* x is read-only, not okay! */

Now, since the array initializer must be a constant expression,
you are out of luck.

--
Alex Monjushko (mo*******@hotm ail.com)
Nov 14 '05 #16
[I snipped some gcc diagnostics from a previous poster here]

In article <news:a8******* *************** ****@posting.go ogle.com>
Chris Mantoulidis <cm****@yahoo.c om> writes:
Okay, this is really weird. here are the 2 programs I compiled:
It is not all that weird, really :-)

[program 1 snipped, might as well go with the all-"const"-qualified version]and (2)
int main(int argc, char **argv) {
const char *const a[] = {"A"}; //constant pointer AND constand data
const char *const b[] = {"B"};
const char *const *z[] = {a,b};
return 0;
}
-----

I compiled both with GCC 3.3.2 like
$gcc -Wall -std=c99 -pedantic const_test_1.c
$gcc -Wall -std=c99 -pedantic const_test_2.c

Only reply I got was:
const_test_1.c : In function "main":
const_test_1.c :4: warning: unused variable `z'
(the same for the other file)


Try with -std=c89 instead of "-std=c99" (or, equivalently but the
only option available in older versions of gcc, "-ansi -pedantic");
the result should differ. Here is why.

First, "const" in C never means "constant". Its meaning is much
more like "read-only variable". In particular, this means that:

static const int size = 10;
static int a[size];

is *always* an error, in both C89 and C99, because arrays with
"static duration" (not quite the same thing as the "static" keyword)
must have integer constant expressions for any specified sizes.
(But -- while this is off-topic -- we might note that this works
fine in C++, where "const" *does* mean "constant" whenever possible.)
In C, a read-only variable is still a variable, and in some situations
is even *supposed* to change -- just not by being written-on in
the C code you are writing. For instance, the Standard specifically
allows one to write:

extern const volatile int tick_counter;

and arrange for one's system to "hook up" this variable to some
sort of constantly-running system clock (CPU clock, external timer,
or whatever). If this tick counter "ticks" at a known speed,
the clock() function might even be as simple as:

/* NB: the name "tick_count er" is not in the implementor's space
so if this were a real implementation we might want to use some
other variable name. */
clock_t clock(void) { return tick_counter; }

The "const" here means that you, the programmer, cannot change it,
but not that it is constant; and the "volatile" means that something
outside the C code changes it, so that the compiler cannot simply
read the variable once and then "remember" its value forever.

(Without the "volatile", the compiler is still supposed to treat
this as a read-only variable -- not a constant -- but *is* allowed
to assume it never changes as well. If tick_counter is never
explicitly initialized, it is implicitly initially zero, so a
compiler could assume that it is *always* zero and just "return 0"
-- not a very good clock() function.)

With that out of the way, consider the local variables again,
and compare against this code:

int main(void) {
int one = 1, two = 2;
int a[2] = { 1, 2 }; /* works in C89 and C99 */
int b[2] = { one, two }; /* works in C99 but not C89 */

return 0;
}

Here, "one" and "two" are clearly ordinary variables -- they are not
even "const"-qualified read-only variables. The initializers for
"b" are thus not at all constants, but C99 accepts this, just as
both C89 and C99 would accept:

int three = one + two;

The difference here is that C99 has extended the set of values
allowed in "aggregate initializers" -- the set of values in the
braces that initialize a[] and b[]. In C89, all aggregate initializers
had to be constant-expressions; in C99, they may be fully-general
expressions as long as they are initializing "automatic duration"
variables (meaning, pretty much, "ordinary local variables").
This means we can even write:

int f(int zog) {
int arr[4] = { zog, 0, 0, zog + 3 };
... more code ...
}

-- but only in C99, not in C89.

Finally, although it is not used in the original poster's problem,
there is one more significant change in C99 that relates back to
"const" meaning read-only rather than constant. C99 adds a new
type of array called a "variable length array" or VLA. Instead of
making the array "arr" have size 4, we can now do this:

int f(int zog) {
int arr[zog];
...
}

This array has all the usual attributes, plus one more -- its size
is determined at runtime. The expression:

sizeof arr

actually multiplies the value of "zog" by sizeof(int) at runtime.
VLAs have some interesting pitfalls -- the draft C99 standard I
keep handy notes that "unusual" control flow into a block (e.g.,
via a "goto") may not be allocated properly. (More precisely,
it says that "the behavior is undefined" if you jump into a block
that declares a VLA, rather than sequentially executing into it.
There are a couple of different "likely" compilation techniques
that give somewhat different but always bizarre results having to
do with not allocating space at the right point. These include
losing local variables and return addresses when control flows
back out of the block -- your code could crash in such a way that
even a good debugger cannot figure out what happened.)

In any case, VLAs can obscure the fact that "const" variables
are still variables. Compare these three functions:

int f1(int zog) { int arr[zog]; ... }
int f2(int n) { const int zog = n; int arr[zog]; ... }
int f3(void) { const int zog = 12; int arr[zog]; ... }

In f1(), it is obvious that "zog" is a variable. In f2(), "zog"
is *still* a variable, despite being "const"-qualified -- and in
f3(), "zog" is again still a variable, despite being const-qualified
and "obviously" always 12.

In all three functions, "arr" is a VLA, and "sizeof arr" is supposed
to be computed at runtime. In f3(), a C99 compiler is allowed to
"cheat": clearly you promised that zog is always exactly 12 -- by
making it 12 initially, promising never to change it, and not saying
that it might be changed "by magic" ("volatile") -- so the compiler
can replace each "zog" by 12, but only after emitting any required
diagnostics. (In this case, there are no required diagnostics.)

On the other hand, if we change "int arr[zog]" to "static int
arr[zog]", or if we are using a C89 compiler, VLAs are no longer
allowed. In this case, all three variants (f1, f2, f3) require
diagnostics (or more precisely, a C compiler has to emit "at least
one" diagnostic for the translation unit -- producing a single
warning, even though there are at least three errors, suffices to
meet the "letter of the law" as it were).

In summary:

- "const" never means "constant", but rather merely "read-only".

- Variables, even if read-only, are not constant expressions
and cannot be used where constant expressions are required.

- If a C compiler can prove that a read-only variable is always
some particular value, it can substitute in that value, but
only after emitting any required diagnostic.

- C89 requires constant expressions in quite a few more places
than does C99, including aggregate initializers and array sizes.
In particular, C99 removes the silly restriction in C89, where
(as a local variable):
int a = b;
is OK, but:
int a[1] = { b };
is not; and C99 adds variable length arrays.

Thus, if you have a C99 compiler, it may provide a better illusion
of const-qualified variables "acting like" constants, simply because
it allows variables in places C89 did not. But const-qualified
variables are still not constants, and sometimes only a "#define"
will do. (C's actual constants -- members of an "enum" type --
only give you integral constant expressions, i.e., not floating
point, and in practice may not be wide enough, e.g., you probably
cannot get a "long long" constant.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
13286
by: Victor Hannak | last post by:
I have a class that needs to reference a const array in several of its methods. Where should I put the declaration/initialization of this array so that it is only created once when the class is instantiated, but is visible to all of the methods of only this class ? const unsigned short ConstantVectorWidth = 10; const float ConstantVector = {5,10,15,20,25,30,35,40,45,50}; Does this syntax look correct?
7
2839
by: Michael Klatt | last post by:
Is there any practical difference between a local variable in main() declared 'const' and one declared 'static const'? int main() { static const int i1(0); const int i2(0); return 0; }
7
4370
by: al | last post by:
char s = "This string literal"; or char *s= "This string literal"; Both define a string literal. Both suppose to be read-only and not to be modified according to Standard. And both have type of "const char *". Right? But why does the compiler I am using allow s to be modified, instead of generating compile error?
2
2504
by: Pavel | last post by:
I am writing software for an embedded application and here is the question. GCC would emit data declared like const char text = "abc"; to .rodata (i.e. "read only data") section. I can put this section to flash memory and that would be OK. I have a structure with one member of it being const char** array;
15
3348
by: candy_init | last post by:
hi, Can anyboby please tell me that why the following code is'nt compiling: int main(void) { const int a=5; int buf; return 0; }
4
21716
by: Bilgehan.Balban | last post by:
Hi, The following code: #include <stdio.h> // const int const_asize = 10; #define define_asize = 10; int array = {1,2,3,4,5,6,7,8,9,0};
0
1879
by: d3x0xr | last post by:
Heh, spelled out in black and white even :) Const is useles... do NOT follow the path of considering any data consatant, because in time, you will have references to it that C does not handle, and you'll be left with just noisy compiler warnings and confusion. if you start a project with all char *, and char ** and even char ***, if you begin at the low level weeding out references of 'passing const char * to char * ( such as...
9
10534
by: Peithon | last post by:
Hi, This is a very simple question but I couldn't find it in your FAQ. I'm using VC++ and compiling a C program, using the /TC flag. I've got a function for comparing two strings int strspcmp(const char * s1, const char * s2) {
10
5979
by: Stephen Howe | last post by:
Hi Just going over some grey areas in my knowledge in C++: 1) If I have const int SomeConst = 1; in a header file, it is global, and it is included in multiple translations units, but it is unused, I know that it does not take up storage in the
0
9811
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9657
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10822
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10532
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
10241
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7774
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6975
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
4443
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4003
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.