Discussion:
error: initializer element is not constant|
(too old to reply)
jak
2017-05-08 07:55:00 UTC
Permalink
Hello to all,
Is there any way, in standard C, to write something like this without
getting an error?

static char *Date = "2017-05-08";

static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
jak
2017-05-08 08:05:47 UTC
Permalink
Post by jak
Hello to all,
Is there any way, in standard C, to write something like this without
getting an error?
static char *Date = "2017-05-08";
static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
... of course, if 'Date' becomes a #define everything works well but I
would change its value at runtime.
Noob
2017-05-08 08:38:48 UTC
Permalink
Post by jak
Is there any way, in standard C, to write something like this without
getting an error?
static char *Date = "2017-05-08";
static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
Define 'Date' as an array.

static const char Date[] = "2017-05-08";

On an unrelated subject, have a look at the __DATE__ macro.
Obviously, embedding time-related strings in a program makes
builds non-deterministic (compiling the same source on different
days will produce different binaries).

Regards.
jak
2017-05-08 09:55:33 UTC
Permalink
Post by Noob
Post by jak
Is there any way, in standard C, to write something like this without
getting an error?
static char *Date = "2017-05-08";
static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
Define 'Date' as an array.
static const char Date[] = "2017-05-08";
On an unrelated subject, have a look at the __DATE__ macro.
Obviously, embedding time-related strings in a program makes
builds non-deterministic (compiling the same source on different
days will produce different binaries).
Regards.
Thank you for your answer and I take this opportunity to ask another
question:

char *Date = "01-01-80";

typedef char * ch;

ch foo;
foo = "01-01-80"; <-- this line

warning: data definition has no type or storage class
warning: type defaults to 'int' in declaration of 'foo'-Wimplicit-int
error: conflicting types for 'foo'
warning: initialization makes integer from pointer without a cast

What am I not understanding?
thanks in advance
bartc
2017-05-08 10:01:52 UTC
Permalink
Post by jak
Post by Noob
Post by jak
Is there any way, in standard C, to write something like this without
getting an error?
static char *Date = "2017-05-08";
static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
Define 'Date' as an array.
static const char Date[] = "2017-05-08";
On an unrelated subject, have a look at the __DATE__ macro.
Obviously, embedding time-related strings in a program makes
builds non-deterministic (compiling the same source on different
days will produce different binaries).
Regards.
Thank you for your answer and I take this opportunity to ask another
char *Date = "01-01-80";
typedef char * ch;
ch foo;
foo = "01-01-80"; <-- this line
warning: data definition has no type or storage class
warning: type defaults to 'int' in declaration of 'foo'-Wimplicit-int
error: conflicting types for 'foo'
warning: initialization makes integer from pointer without a cast
What am I not understanding?
thanks in advance
Have you put those lines inside a function? Try:

int main (void) {

ch foo;

foo = "01-01-80";
}

Otherwise, the assignment to foo probably looks like a new declaration
of something called 'foo', which is assumed to be an 'int' type. In C,
declaring the type of a variable is optional, so the compiler thought it
was this:

ch foo;
int foo = "01-01-80";

(Pretty stupid of the language to allow that, but no compiler has wanted
to be the first to ban it outright, it case some ancient code no longer
works.)
--
bartc
jak
2017-05-08 10:18:29 UTC
Permalink
Post by bartc
Post by jak
Post by Noob
Post by jak
Is there any way, in standard C, to write something like this without
getting an error?
static char *Date = "2017-05-08";
static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
Define 'Date' as an array.
static const char Date[] = "2017-05-08";
On an unrelated subject, have a look at the __DATE__ macro.
Obviously, embedding time-related strings in a program makes
builds non-deterministic (compiling the same source on different
days will produce different binaries).
Regards.
Thank you for your answer and I take this opportunity to ask another
char *Date = "01-01-80";
typedef char * ch;
ch foo;
foo = "01-01-80"; <-- this line
warning: data definition has no type or storage class
warning: type defaults to 'int' in declaration of 'foo'-Wimplicit-int
error: conflicting types for 'foo'
warning: initialization makes integer from pointer without a cast
What am I not understanding?
thanks in advance
int main (void) {
ch foo;
foo = "01-01-80";
}
Otherwise, the assignment to foo probably looks like a new declaration
of something called 'foo', which is assumed to be an 'int' type. In C,
declaring the type of a variable is optional, so the compiler thought it
ch foo;
int foo = "01-01-80";
(Pretty stupid of the language to allow that, but no compiler has wanted
to be the first to ban it outright, it case some ancient code no longer
works.)
Thanks a lot for responding but the 'very stupid' is me, because I did
the copy/paste the wrong lines :(

I would like to create an array of pointers, of pointers to strings. In
this way I can have the pointers as constant and I wrote this:

char *Date = "01-01-80";

typedef char * ch;
typedef ch * p_ch;

p_ch foo[] =
{
&Date,
(p_ch)&"Date"
};

This works but I do not know how to declare foo without using typedef.
bartc
2017-05-08 11:02:55 UTC
Permalink
Post by jak
I would like to create an array of pointers, of pointers to strings. In
char *Date = "01-01-80";
typedef char * ch;
typedef ch * p_ch;
p_ch foo[] =
{
&Date,
(p_ch)&"Date"
};
This works but I do not know how to declare foo without using typedef.
Those types would look like this without typedefs:

char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];

(The arrays will need a dimension, or need to be initialised.)

But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.

I don't think you can apply a cast to "ABC" to get the pointer you need.
(Well, you can cast it, but it won't be a proper pointer to string,
it'll just be a string, and will crash when you apply the dereference
below.)

Using the array would be harder too as you'll need an extra dereference
to extract the string:

puts(*array_of_ptr_to_str[0]);
--
Bartc
Keith Thompson
2017-05-08 16:00:50 UTC
Permalink
bartc <***@freeuk.com> writes:
[...]
Post by bartc
char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];
(The arrays will need a dimension, or need to be initialised.)
But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.
I think you meant that arrays of pointers to arrays would be unusual.

A "pointer to a string" is by definition a pointer to the initial
character of a string. Arrays of pointers to strings are quite common;
for example, argv points to the initial element of such an array.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
bartc
2017-05-08 16:50:41 UTC
Permalink
Post by Keith Thompson
[...]
Post by bartc
char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];
(The arrays will need a dimension, or need to be initialised.)
But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.
I think you meant that arrays of pointers to arrays would be unusual.
No, I mean arrays of pointers to strings, with a string meaning char*.
The variable names I've chosen should make it clear that:

str (ie. string) is a char*
ptr_to_str is char**

and so on.

Since it is impossible to work with an actual string itself, it's more
useful I think for 'string' to be a synonym for 'char*'.
Post by Keith Thompson
A "pointer to a string" is by definition a pointer to the initial
character of a string.
AFAIK C has no such concept. It only has pointer to char. Or, rarely, a
pointer to an entire array, of which the contents may contain a
zero-terminated string.
--
bartc
Keith Thompson
2017-05-08 18:37:20 UTC
Permalink
[...]
Post by bartc
Post by Keith Thompson
I think you meant that arrays of pointers to arrays would be unusual.
No, I mean arrays of pointers to strings, with a string meaning char*.
str (ie. string) is a char*
ptr_to_str is char**
and so on.
Then you are using terminology that is clearly defined by the C standard
in a manner inconsistent with the way the standard uses it.
Post by bartc
Since it is impossible to work with an actual string itself, it's more
useful I think for 'string' to be a synonym for 'char*'.
Whether it would have been more useful or not, the standard clearly
defines the terms "string" and "pointer to string" in 7.1.1p1, which
I've recently quoted elsewhere in this thread.
Post by bartc
Post by Keith Thompson
A "pointer to a string" is by definition a pointer to the initial
character of a string.
AFAIK C has no such concept.
Well now you know that it does.
Post by bartc
It only has pointer to char. Or, rarely, a
pointer to an entire array, of which the contents may contain a
zero-terminated string.
One more time, N1570 7.1.1p1 (with asterisks to represent italics, which
denote a definition of a term):

A *string* is a contiguous sequence of characters terminated
by and including the first null character. The term *multibyte
string* is sometimes used instead to emphasize special processing
given to multibyte characters contained in the string or to
avoid confusion with a wide string. A *pointer to a string*
is a pointer to its initial (lowest addressed) character.

Feel free to dislike those definitions, but at least consider
acknowledging their existence in the C standard.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
bartc
2017-05-08 18:49:44 UTC
Permalink
Post by Keith Thompson
[...]
Post by bartc
Post by Keith Thompson
I think you meant that arrays of pointers to arrays would be unusual.
No, I mean arrays of pointers to strings, with a string meaning char*.
str (ie. string) is a char*
ptr_to_str is char**
and so on.
Then you are using terminology that is clearly defined by the C standard
in a manner inconsistent with the way the standard uses it.
Post by bartc
Since it is impossible to work with an actual string itself, it's more
useful I think for 'string' to be a synonym for 'char*'.
Whether it would have been more useful or not, the standard clearly
defines the terms "string" and "pointer to string" in 7.1.1p1, which
I've recently quoted elsewhere in this thread.
So you call a 'pointer to char', a 'pointer to string'.

OK.
--
bartc
Ben Bacarisse
2017-05-08 19:13:30 UTC
Permalink
Post by bartc
Post by Keith Thompson
[...]
Post by bartc
Post by Keith Thompson
I think you meant that arrays of pointers to arrays would be unusual.
No, I mean arrays of pointers to strings, with a string meaning char*.
str (ie. string) is a char*
ptr_to_str is char**
and so on.
Then you are using terminology that is clearly defined by the C standard
in a manner inconsistent with the way the standard uses it.
Post by bartc
Since it is impossible to work with an actual string itself, it's more
useful I think for 'string' to be a synonym for 'char*'.
Whether it would have been more useful or not, the standard clearly
defines the terms "string" and "pointer to string" in 7.1.1p1, which
I've recently quoted elsewhere in this thread.
So you call a 'pointer to char', a 'pointer to string'.
Only if it points to a character in a string. Not all char *s do that.
--
Ben.
Keith Thompson
2017-05-08 19:44:53 UTC
Permalink
Post by bartc
Post by Keith Thompson
[...]
Post by bartc
Post by Keith Thompson
I think you meant that arrays of pointers to arrays would be unusual.
No, I mean arrays of pointers to strings, with a string meaning char*.
str (ie. string) is a char*
ptr_to_str is char**
and so on.
Then you are using terminology that is clearly defined by the C standard
in a manner inconsistent with the way the standard uses it.
Post by bartc
Since it is impossible to work with an actual string itself, it's more
useful I think for 'string' to be a synonym for 'char*'.
Whether it would have been more useful or not, the standard clearly
defines the terms "string" and "pointer to string" in 7.1.1p1, which
I've recently quoted elsewhere in this thread.
So you call a 'pointer to char', a 'pointer to string'.
I call a char* value a "pointer to a string" if and only if it points to
the initial character of a string. A null char* pointer is not a
pointer to a string.

Do you find the definitions I quoted unclear?

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Scott Lurndal
2017-05-08 20:24:52 UTC
Permalink
Post by bartc
Post by Keith Thompson
[...]
Post by bartc
Post by Keith Thompson
I think you meant that arrays of pointers to arrays would be unusual.
No, I mean arrays of pointers to strings, with a string meaning char*.
str (ie. string) is a char*
ptr_to_str is char**
and so on.
Then you are using terminology that is clearly defined by the C standard
in a manner inconsistent with the way the standard uses it.
Post by bartc
Since it is impossible to work with an actual string itself, it's more
useful I think for 'string' to be a synonym for 'char*'.
Whether it would have been more useful or not, the standard clearly
defines the terms "string" and "pointer to string" in 7.1.1p1, which
I've recently quoted elsewhere in this thread.
So you call a 'pointer to char', a 'pointer to string'.
"char *" defines a pointer to a character in the same fashion as
"int *" defines a pointer to an integer. The use of the autoincrement
operator to step sequentially through contiguous char values until
some terminal value is encountered doesn't change the fact that a
"char *" points to a character, not a string.

Strings are just a character array with the convention that it
is terminated by a char with the value zero.
jak
2017-05-09 07:54:23 UTC
Permalink
Post by bartc
Post by jak
I would like to create an array of pointers, of pointers to strings. In
char *Date = "01-01-80";
typedef char * ch;
typedef ch * p_ch;
p_ch foo[] =
{
&Date,
(p_ch)&"Date"
};
This works but I do not know how to declare foo without using typedef.
char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];
(The arrays will need a dimension, or need to be initialised.)
But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.
I don't think you can apply a cast to "ABC" to get the pointer you need.
(Well, you can cast it, but it won't be a proper pointer to string,
it'll just be a string, and will crash when you apply the dereference
below.)
Using the array would be harder too as you'll need an extra dereference
puts(*array_of_ptr_to_str[0]);
Ok ok. Bugs have also been put in the middle. The first time I wrote the
declaration in this way:

char *Date = "01-01-80";
char **Phrases[]
{
&Date
}

and gcc gave me a lot of errors. For this reason I chosed the way of
typedefs. Later closed CodeBlocks and reopened it, and also this
statement worked. :(

Now I'm using this work around:


char *Phrases[]
{
"Date: ",
NULL,
"\r\n"
};
char **DatePos = Phrases[1];

foo()
{
*DatePos = ctime(&t);
*DatePos[strlen(Date) - 1] = '\0';
}

But I still do not understand why the compiler does not allow me this:

char *Date = NULL;
char *Phrases[]
{
"Date: ",
Date,
"\r\n"
};

In the end I'm just asking him to allocate space to write in an address
exactly as it happens when I write NULL instead of 'Date'.
jak
2017-05-09 08:15:15 UTC
Permalink
Post by jak
char *Phrases[]
{
"Date: ",
NULL,
"\r\n"
};
char **DatePos = Phrases[1];
foo()
{
*DatePos = ctime(&t);
*DatePos[strlen(Date) - 1] = '\0';
}
Oops:

char *Phrases[]
{
"Date: ",
NULL,
"\r\n"
};
char *DatePos = Phrases[1];

foo()
{
DatePos = ctime(&t);
DatePos[strlen(Date) - 1] = '\0';
}
GOTHIER Nathan
2017-05-09 10:12:42 UTC
Permalink
On Tue, 9 May 2017 09:54:23 +0200
Post by jak
char *Phrases[]
{
"Date: ",
NULL,
"\r\n"
};
What kind of object is this? An array or a structure?
bartc
2017-05-09 10:47:35 UTC
Permalink
Post by jak
Post by bartc
Post by jak
I would like to create an array of pointers, of pointers to strings. In
char *Date = "01-01-80";
typedef char * ch;
typedef ch * p_ch;
p_ch foo[] =
{
&Date,
(p_ch)&"Date"
};
This works but I do not know how to declare foo without using typedef.
char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];
(The arrays will need a dimension, or need to be initialised.)
But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.
I don't think you can apply a cast to "ABC" to get the pointer you need.
(Well, you can cast it, but it won't be a proper pointer to string,
it'll just be a string, and will crash when you apply the dereference
below.)
Using the array would be harder too as you'll need an extra dereference
puts(*array_of_ptr_to_str[0]);
Ok ok. Bugs have also been put in the middle. The first time I wrote the
char *Date = "01-01-80";
char **Phrases[]
{
&Date
}
and gcc gave me a lot of errors.
Not surprising as you've left out "=" after "[]", and ";" after "}". You
should try and post exact code.

After fixing that, it seemed to compile. Date has type char*; &Date has
type char**; Phrases has type char**[], and each element needs to be
type char**, so &Date matches (also surprising as it looked wrong).

Then this works:

puts(*Phrases[0]);
Post by jak
char *Date = NULL;
char *Phrases[]
{
"Date: ",
Date,
"\r\n"
};
In the end I'm just asking him to allocate space to write in an address
exactly as it happens when I write NULL instead of 'Date'.
Does it say it an initialiser is not constant?

NULL is just 0.

Date requires a memory access to get the NULL stored in it. Memory
accesses only take place at runtime.

You can make this work by putting it inside a function. But then those
memory accesses needed to build Phrases will happen every time you call
the function. (Maybe, you can call the function once to set up a version
of Phrases[] which is then copied to the Phrases declared outside the
functions.)

But it's still not clear what you're trying to achieve.

Here's a normal list of strings:

char *List1[] = {"one", "two", "three"};

Here's an indirect one (list of pointers to strings):

char *A="uno", *B="due", *C="tre";
char **List2[] = {&A, &B, &C};

And you access them like this:

puts(List1[0]);
puts(List1[1]);
puts(List1[2]);

puts(*List2[0]);
puts(*List2[1]);
puts(*List2[2]);

What do you want to do that is different?
--
Bartc
jak
2017-05-09 17:06:57 UTC
Permalink
Post by bartc
Post by jak
Post by bartc
Post by jak
I would like to create an array of pointers, of pointers to strings. In
char *Date = "01-01-80";
typedef char * ch;
typedef ch * p_ch;
p_ch foo[] =
{
&Date,
(p_ch)&"Date"
};
This works but I do not know how to declare foo without using typedef.
char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];
(The arrays will need a dimension, or need to be initialised.)
But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.
I don't think you can apply a cast to "ABC" to get the pointer you need.
(Well, you can cast it, but it won't be a proper pointer to string,
it'll just be a string, and will crash when you apply the dereference
below.)
Using the array would be harder too as you'll need an extra dereference
puts(*array_of_ptr_to_str[0]);
Ok ok. Bugs have also been put in the middle. The first time I wrote the
char *Date = "01-01-80";
char **Phrases[]
{
&Date
}
and gcc gave me a lot of errors.
Not surprising as you've left out "=" after "[]", and ";" after "}". You
should try and post exact code.
After fixing that, it seemed to compile. Date has type char*; &Date has
type char**; Phrases has type char**[], and each element needs to be
type char**, so &Date matches (also surprising as it looked wrong).
puts(*Phrases[0]);
Post by jak
char *Date = NULL;
char *Phrases[]
{
"Date: ",
Date,
"\r\n"
};
In the end I'm just asking him to allocate space to write in an address
exactly as it happens when I write NULL instead of 'Date'.
Does it say it an initialiser is not constant?
NULL is just 0.
Date requires a memory access to get the NULL stored in it. Memory
accesses only take place at runtime.
You can make this work by putting it inside a function. But then those
memory accesses needed to build Phrases will happen every time you call
the function. (Maybe, you can call the function once to set up a version
of Phrases[] which is then copied to the Phrases declared outside the
functions.)
But it's still not clear what you're trying to achieve.
char *List1[] = {"one", "two", "three"};
char *A="uno", *B="due", *C="tre";
char **List2[] = {&A, &B, &C};
puts(List1[0]);
puts(List1[1]);
puts(List1[2]);
puts(*List2[0]);
puts(*List2[1]);
puts(*List2[2]);
What do you want to do that is different?
No, I do not want anything different. Only I can not understand the
reason why the compiler wants the initializer to be constant. When I
write this:

char *Phrase[] =
{
NULL, /*1*/
NULL, /*2*/
NULL, /*3*/
NULL /*4*/
};

I ask the compiler to allocate for me 4 contiguous memory areas, each
large to contain a pointer. Each pointer is char type and then uses this
step in its arithmetic. If at runtime I can modify, with new values,
each of the 4 pointers I have declared; Why does the compiler want it to
be constant during the definition? Is there a real reason, or is it just
the imagination of those who have thought about grammar and syntax?

Please, excuse my English.
Scott Lurndal
2017-05-09 17:10:55 UTC
Permalink
Post by jak
No, I do not want anything different. Only I can not understand the
reason why the compiler wants the initializer to be constant. When I
char *Phrase[] =
{
NULL, /*1*/
NULL, /*2*/
NULL, /*3*/
NULL /*4*/
};
I ask the compiler to allocate for me 4 contiguous memory areas, each
large to contain a pointer. Each pointer is char type and then uses this
step in its arithmetic. If at runtime I can modify, with new values,
each of the 4 pointers I have declared; Why does the compiler want it to
be constant during the definition?
Because you're defining file-scope static data, which must
be fully resolved at compile time since it will be stored in
the executable (ELF, PE/COFF), long before run-time.
jak
2017-05-09 17:20:41 UTC
Permalink
Post by Scott Lurndal
Post by jak
No, I do not want anything different. Only I can not understand the
reason why the compiler wants the initializer to be constant. When I
char *Phrase[] =
{
NULL, /*1*/
NULL, /*2*/
NULL, /*3*/
NULL /*4*/
};
I ask the compiler to allocate for me 4 contiguous memory areas, each
large to contain a pointer. Each pointer is char type and then uses this
step in its arithmetic. If at runtime I can modify, with new values,
each of the 4 pointers I have declared; Why does the compiler want it to
be constant during the definition?
Because you're defining file-scope static data, which must
be fully resolved at compile time since it will be stored in
the executable (ELF, PE/COFF), long before run-time.
Ok. Then return to the first question. What information is missing from
the compiler to solve this?

char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};

...and why does it solve this?

char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";

char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Barry Schwarz
2017-05-09 17:35:53 UTC
Permalink
Post by jak
Post by Scott Lurndal
Post by jak
No, I do not want anything different. Only I can not understand the
reason why the compiler wants the initializer to be constant. When I
char *Phrase[] =
{
NULL, /*1*/
NULL, /*2*/
NULL, /*3*/
NULL /*4*/
};
I ask the compiler to allocate for me 4 contiguous memory areas, each
large to contain a pointer. Each pointer is char type and then uses this
step in its arithmetic. If at runtime I can modify, with new values,
each of the 4 pointers I have declared; Why does the compiler want it to
be constant during the definition?
Because you're defining file-scope static data, which must
be fully resolved at compile time since it will be stored in
the executable (ELF, PE/COFF), long before run-time.
Ok. Then return to the first question. What information is missing from
the compiler to solve this?
char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};
...and why does it solve this?
char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";
char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Possibly because the address of a static variable is a compile time
const (note const, not constant) while the value of a static variable
is not.
--
Remove del for email
jak
2017-05-09 18:04:40 UTC
Permalink
Post by Barry Schwarz
Post by jak
Ok. Then return to the first question. What information is missing from
the compiler to solve this?
char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};
...and why does it solve this?
char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";
char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Possibly because the address of a static variable is a compile time
const (note const, not constant) while the value of a static variable
is not.
You would be right if the compiler information was not the same in both
cases. Also at runtime you can change any value in * Phrase [] and in **
Phrase [], too, so why const? I'm afraid it's just a syntactic
imposition. :(
Keith Thompson
2017-05-09 18:57:15 UTC
Permalink
Post by jak
Post by Barry Schwarz
Post by jak
Ok. Then return to the first question. What information is missing from
the compiler to solve this?
char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};
...and why does it solve this?
char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";
char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Possibly because the address of a static variable is a compile time
const (note const, not constant) while the value of a static variable
is not.
You would be right if the compiler information was not the same in both
cases. Also at runtime you can change any value in * Phrase [] and in **
Phrase [], too, so why const? I'm afraid it's just a syntactic
imposition. :(
The language standard has to have some consistent definition of what is
or is not a constant expression. It can't just say "anything whose
value the compiler can figure out is a constant expression"; that would
imply that the criteria could change depending on how clever the
compiler happens to be.

In general, the standard doesn't require compilers to perform data flow
analysis.

Let's take a simple example:

char *foo = "hello";
char *bar = foo;

In this case, sure, a compiler *could* perform an analysis that
determines that the value of foo, when it's used in an initializer
for the static object bar, cannot have changed from its initial
value. But although the compiler must generate code that will
cause foo to be properly initialized before entry to main(), it's
not required to remember what that initial value is. It would have
to do so to be able to implement those declarations.

On the other hand, given:

char foo[] = "hello";
char *bar = foo;

the expression `foo` in the initializer yields the address of a
static object, not the (current) value of that object. The compiler
has to be able to generate code that refers to the address of a
static object anyway, so there's no extra burden in requiring it
to treat such an address as a compile-time constant expression.

Given modern optimizing compiler technology, it might be possible to
loosen the rules for constant expressions by requiring *some* data
flow analysis. But (a) that would still impose an extra burden
on small non-optimizing compilers, and (b) defining the exact
new rules in Standardese would be a difficult task (and reaching
agreement on just what those rules should be would be even harder).
A small tweak to the rules, to cover just a case like this one,
might partially avoid those problems, but it's unlikely that it
would be considered worthwhile. The committee isn't going to change
the language to fix a problem that already has a workaround.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
s***@casperkitty.com
2017-05-09 19:50:40 UTC
Permalink
Post by Keith Thompson
char foo[] = "hello";
char *bar = foo;
the expression `foo` in the initializer yields the address of a
static object, not the (current) value of that object. The compiler
has to be able to generate code that refers to the address of a
static object anyway, so there's no extra burden in requiring it
to treat such an address as a compile-time constant expression.
Actually, in some cases the latter may be a significant burden, but it is
one that the authors of the C Standard thought was worthwhile to impose.
Most notably, there are some platforms where static variables are accessed
using a displacement from an address register. Such a design makes it
practical for a system without a memory-management unit (e.g. the classic
Macintosh) to have multiple applications in memory simultaneously but means
that after a program is loaded into memory as a blob, the startup code will
need to patch all static objects that are initialized to hold addresses of
functions or other static objects.
Keith Thompson
2017-05-09 19:54:18 UTC
Permalink
Post by s***@casperkitty.com
Post by Keith Thompson
char foo[] = "hello";
char *bar = foo;
the expression `foo` in the initializer yields the address of a
static object, not the (current) value of that object. The compiler
has to be able to generate code that refers to the address of a
static object anyway, so there's no extra burden in requiring it
to treat such an address as a compile-time constant expression.
Actually, in some cases the latter may be a significant burden, but it is
one that the authors of the C Standard thought was worthwhile to impose.
Most notably, there are some platforms where static variables are accessed
using a displacement from an address register. Such a design makes it
practical for a system without a memory-management unit (e.g. the classic
Macintosh) to have multiple applications in memory simultaneously but means
that after a program is loaded into memory as a blob, the startup code will
need to patch all static objects that are initialized to hold addresses of
functions or other static objects.
I said it's no *extra* burden. It's a burden that's required for
handling static objects at all.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
bartc
2017-05-09 19:15:56 UTC
Permalink
Post by jak
Post by Barry Schwarz
Post by jak
Ok. Then return to the first question. What information is missing from
the compiler to solve this?
char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};
...and why does it solve this?
char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";
char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Possibly because the address of a static variable is a compile time
const (note const, not constant) while the value of a static variable
is not.
You would be right if the compiler information was not the same in both
cases. Also at runtime you can change any value in * Phrase [] and in **
Phrase [], too, so why const? I'm afraid it's just a syntactic
imposition. :(
Yes, it's a rule about what kind of expressions are allowed. Sometimes,
as here, it might be 'obvious' what value should be used. But in general
it's not possible to evaluate such expressions, or they are ambiguous.

This is the rule:

int A=1200;
int B=A;

This is not allowed. But you can do this:

#define K 1200
int A=K;
int B=K;

or:

int A=1200;
int main(void){
int B=A;
...
--
bartc
James R. Kuyper
2017-05-09 18:13:05 UTC
Permalink
...
Post by Barry Schwarz
Post by jak
Ok. Then return to the first question. What information is missing from
the compiler to solve this?
It's not that the information is missing - but that the C standard
doesn't require implementation to figure it out.
Post by Barry Schwarz
Post by jak
char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};
...and why does it solve this?
char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";
char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Possibly because the address of a static variable is a compile time
const (note const, not constant) while the value of a static variable
is not.
Note, in particular, that the unnamed array of char in which "01-01-80"
is stored has static storage duration (6.4.5p6), and that the value of
that string literal, which is automatically converted into a pointer to
the first element of that array, is therefore a perfectly legitimate
address constant (6.6p8). A sufficient intelligent compiler could have
noticed that they have the same value, and initialized Phrase
accordingly - but the C standard doesn't require the compiler to be that
bright: "... the value of an object shall not be accessed ..." (6.6p9).

Trivial work-arounds:

char Date[] = "01-01-80";

or

#define Date "01-01-80"
Keith Thompson
2017-05-09 18:41:25 UTC
Permalink
[...]
Post by Barry Schwarz
Post by jak
Ok. Then return to the first question. What information is missing from
the compiler to solve this?
char *Date = "01-01-80";
char *Phrase[] =
{
NULL, /*1*/
Date, /*2*/
NULL, /*3*/
NULL /*4*/
};
...and why does it solve this?
char *DescDate = "Date: ";
char *Date = "01-01-80";
char *CrLf = "\r\n";
char *Text = "Dear friend...";
char **Phrase[] =
{
&DescDate, &Date, &CrLf,
&Text, &CrLf
};
Possibly because the address of a static variable is a compile time
const (note const, not constant) while the value of a static variable
is not.
You got that backwards. The address of a static variable is a compile
time *constant*. Specifically, it's an *address constant* as defined in
N1570 6.6p9.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Ben Bacarisse
2017-05-09 11:16:09 UTC
Permalink
Post by jak
Post by bartc
Post by jak
I would like to create an array of pointers, of pointers to strings. In
char *Date = "01-01-80";
typedef char * ch;
typedef ch * p_ch;
p_ch foo[] =
{
&Date,
(p_ch)&"Date"
};
This works but I do not know how to declare foo without using typedef.
char * str;
char * array_of_str[];
char ** ptr_to_str;
char ** array_of_ptr_to_str[];
(The arrays will need a dimension, or need to be initialised.)
But arrays of pointers to strings would be unusual, and be harder to
initialise as you can't just have "ABC", but need to set up a named
string: char* abc="ABC", then use &abc.
I don't think you can apply a cast to "ABC" to get the pointer you need.
(Well, you can cast it, but it won't be a proper pointer to string,
it'll just be a string, and will crash when you apply the dereference
below.)
Using the array would be harder too as you'll need an extra dereference
puts(*array_of_ptr_to_str[0]);
char *Date = "01-01-80";
char **Phrases[]
{
&Date
}
This looks like a typing error. You should cut and paste code.
Post by jak
and gcc gave me a lot of errors.
If that was the code, you will get errors. It's just not correct C. I
suspect you meant to write:

char *Date = "01-01-80";
char **Phrases[] = {
&Date
};

which should work.

<snip>
Post by jak
char *Phrases[]
{
"Date: ",
NULL,
"\r\n"
};
Are you missing an = again? As shown, this should not work.
Post by jak
char **DatePos = Phrases[1];
And this won't work (because the types don't match) if you have "char
*Phrases" as shown. Programming is about detail, and you will get very
confused with things that seem to work and then don't or change from
working to broken because you don't spot these details.
Post by jak
foo()
{
*DatePos = ctime(&t);
*DatePos[strlen(Date) - 1] = '\0';
This is all wrong. You really need to back-up, take a breath, and
re-think. For a start, *DatePos[strlen(Date) - 1] = '\0'; does not do
what you think. It means *(DatePos[strlen(Date) - 1]) = '\0' and
DatePos does not have that many elements.

What is the ultimate purpose of these pointers and arrays of pointers?
Post by jak
}
char *Date = NULL;
char *Phrases[]
{
"Date: ",
Date,
"\r\n"
};
The main reason is syntax. This is not valid declaration in C. Correct
the syntax and yo may find it compiles. Whether is does what you want
is another matter altogether, but since you don't say what you want, I
can't help with that.
Post by jak
In the end I'm just asking him to allocate space to write in an
address exactly as it happens when I write NULL instead of 'Date'.
--
Ben.
Keith Thompson
2017-05-09 15:11:48 UTC
Permalink
jak <***@nospam.tnx> writes:
[...]
Post by jak
Ok ok. Bugs have also been put in the middle. The first time I wrote the
char *Date = "01-01-80";
char **Phrases[]
{
&Date
}
and gcc gave me a lot of errors.
You have two simple syntax errors. You need an "=" before the
initializer, and a semicolon after it. With those changes, it compiles.

[...]
Post by jak
char *Date = NULL;
char *Phrases[]
{
"Date: ",
Date,
"\r\n"
};
In the end I'm just asking him to allocate space to write in an address
exactly as it happens when I write NULL instead of 'Date'.
The initializer for an object defined at file scope must consist only of
constant expressions. The expression `Date` yields the value of a
variable, which obviously is not constant. (A compiler might be able to
determine that the object hasn't been modified since its initialization,
but that doesn't make its name a constant expression. Adding "const"
wouldn't help either; "const" means read-only, not constant.)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Ben Bacarisse
2017-05-08 11:12:55 UTC
Permalink
<snip>
Post by jak
In C, declaring the type of a variable is optional,
Not for nearly two decades. If you can ask the compiler to follow a
modern standard, you will be told about such things.

<snip>
Post by jak
I would like to create an array of pointers, of pointers to
I think you should back-up a bit. How do you plan to use this data? I
ask because "a pointer to a string" is not well-defined in C. A C
strings are not a type but a format of data (essentially insisting on a
null terminator) so must program represent a "pointer to string" as
char * -- i.e. as a pointer to the first character of the string.
Post by jak
char *Date = "01-01-80";
typedef char * ch;
typedef ch * p_ch;
p_ch foo[] =
{
&Date,
(p_ch)&"Date"
Woop! Woop! Woop!
In C, a cast should alert you to something that needs to be scrutinised.
It often means something is wrong in the design. (Casts that are there
to silence an advisory warning that you otherwise like to see are not
quite the same.)

In this case there is a real problem.
Post by jak
};
This works but I do not know how to declare foo without using typedef.
char **foo[] = { ... };

But you can't point to the pointer that points to "Date". The cast has
simply papered over a real problem. If you need to change the
pointed-to pointers, you will come unstuck when using literal strings.

So, can you say what you are aiming for here?
--
Ben.
bartc
2017-05-08 12:45:41 UTC
Permalink
Post by Ben Bacarisse
<snip>
In C, declaring the type of a variable is optional,
Not for nearly two decades. If you can ask the compiler to follow a
modern standard, you will be told about such things.
If I say -std=c99 or -std=c11 to gcc, it still just gives me a warning
about implicit int.

Ergo, it is still optional.

If I try the same in a language where it's definitely not optional, I
will get a hard error not just a telling-off.
--
bartc
Keith Thompson
2017-05-08 16:04:59 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
<snip>
In C, declaring the type of a variable is optional,
Not for nearly two decades. If you can ask the compiler to follow a
modern standard, you will be told about such things.
If I say -std=c99 or -std=c11 to gcc, it still just gives me a warning
about implicit int.
Ergo, it is still optional.
If I try the same in a language where it's definitely not optional, I
will get a hard error not just a telling-off.
That warning is a diagnostic message about a constraint violation.
It is not optional. (I personally consider it unfortunate that gcc
chooses to issue non-fatal warnings for some constraint violations,
but that can be worked around using the "-pedantic-errors" option.)

In C99 and C11, declaring the type of a variable is not optional.
A program that fails to do so is just as invalid as a program
containing a syntax error. gcc's odd way of diagnosing such errors
is not a language issue (except for the fact that the C standard
permits such treatment).
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Ben Bacarisse
2017-05-08 18:53:57 UTC
Permalink
Post by bartc
Post by Ben Bacarisse
<snip>
In C, declaring the type of a variable is optional,
Not for nearly two decades. If you can ask the compiler to follow a
modern standard, you will be told about such things.
If I say -std=c99 or -std=c11 to gcc, it still just gives me a warning
about implicit int.
Ergo, it is still optional.
No. You are (again) drawing unwarranted conclusions about C from what
gcc tells you.

<snip>
--
Ben.
bartc
2017-05-08 19:44:44 UTC
Permalink
Post by Ben Bacarisse
Post by bartc
Post by Ben Bacarisse
<snip>
In C, declaring the type of a variable is optional,
Not for nearly two decades. If you can ask the compiler to follow a
modern standard, you will be told about such things.
If I say -std=c99 or -std=c11 to gcc, it still just gives me a warning
about implicit int.
Ergo, it is still optional.
No. You are (again) drawing unwarranted conclusions about C from what
gcc tells you.
Most people can only use C via a compiler.

The compilers I've tried don't seem to rigorously enforce the
requirement that variables and functions must have an explicit type:

a=1234; // at file scope

pelles c warning
lccwin warning
dmc nothing
gcc warning
tiny c nothing

All run with default options, except gcc which is the only one where I
know how to specify a standard.

(My own compiler allowed implicit types because I thought it had to. But
now it no longer does so and a hard error is reported.)

Maybe, as Keith suggested, the fault is also with the language in not
requiring such errors to be reported seriously.

(All the compilers on godbolt.org report this as an actual error. But I
think they are compiling as C++ not C.)
--
bartc
Noob
2017-05-09 07:27:08 UTC
Permalink
Post by bartc
The compilers I've tried don't seem to rigorously enforce the
requirement that variables and functions must have an explicit type
This set of flags:

gcc -std=c11 -Wall -Werror -pedantic -pedantic-errors

will put gcc in a mode which is closer to your expectations.
Tim Rentsch
2017-05-09 14:10:54 UTC
Permalink
Post by bartc
If I say -std=c99 or -std=c11 to gcc, it still just gives me a warning
about implicit int.
Use -pedantic-errors (in addition to -std=...).
Keith Thompson
2017-05-08 16:30:47 UTC
Permalink
Ben Bacarisse <***@bsb.me.uk> writes:
[...]
Post by Ben Bacarisse
I think you should back-up a bit. How do you plan to use this data? I
ask because "a pointer to a string" is not well-defined in C.
In fact it is.
Post by Ben Bacarisse
A C
strings are not a type but a format of data (essentially insisting on a
null terminator) so must program represent a "pointer to string" as
char * -- i.e. as a pointer to the first character of the string.
N1570 7.1.1p1:

A *string* is a contiguous sequence of characters terminated by
and including the first null character. [...] A *pointer to a
string* is a pointer to its initial (lowest addressed) character.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
John Bode
2017-05-08 15:05:11 UTC
Permalink
Post by jak
Hello to all,
Is there any way, in standard C, to write something like this without
getting an error?
static char *Date = "2017-05-08";
static char *Phrase[] =
{
"Date: ",
Date,
"\r\n"
};
Does Phrase really need to be static? If so, then you'll have to replace
Date with a string literal or a macro that expands to a string literal:

#define DATE "2017-05-08"

static char *Phrase[] =
{
"Date: ",
DATE,
"\r\n"
};

Since you declared Phrase to be static, you can only use constant
expressions in the initializer.
Loading...