C runs on machines which don't have the ability to trigger such faults.
Yes. But not in any of the cases where I program. I live in the world of
x86 and ARM CPUs. They trigger faults.
But seriously, you think that a plain literal number in a program ought
to have to be explicitly declared constant?
No. I consider a literal number to already to be a constant. It is an
explicit value of determinate quantity used for whatever purpose. However,
if you assign that literal number to something like:
int foo = 5;
....then the variable foo must be declared const if you don't want its value
to change.
Consider a program like this:
Must I?
#include <stdio.h>
int add(int x, int y) {
y = y + x;
x = x + 1;
return y;
}
int main(void) {
int y = 0;
for (i = 0; i < 10; ++i) {
y = add(1, y);
}
printf("y: %d\n", y);
return 0;
}
You think that this program ought to produce, not 10, but some larger value,
because the literal 1 is not declared specifically to be constant, and thus
it ought to be modifiable?
No. I consider all literal numbers to already be constants. What I mean is
that every variable created should be read-write by default, unless explicitly
type qualified as const. In such a case, then it becomes a read-only constant.
Until that time, all variables are read-write.
Example:
char* list[] = { "one", "two", "three" };
In this case, list[0] should contain a writable character array of four bytes,
lines[1] likewise, and list[2] should be six bytes. However, today unless
you use the compound literal syntax on GCC, the string literals are converted
to read-only constants. In my view, that should not be.
I think string literals should only exist as constants when used like this:
printf("Hi, mom!\n");
Or when they are explicitly type qualified, as in:
const char foo[] = "Hi, mom!";
Without using the const prefix, those string literals should always be
converted at compile-time into read-write values.
(Not "will produce", since C is generally pass-by-value, but "should" as a
matter of design philosophy.)
You could use int& x, though it would not work in this case because 1 is
a literal number ... right?
What about non-string literals, like numbers?
See above.
It doesn't sound like a "version of C".
It uses nearly all C syntax and conventions. It just greatly relaxes many
restraints and constraints, converting errors into warnings. This code
will not compile in Visual C++ without an error:
#include <stdlib.h>
int main(int argc, char* argv[])
{
union {
char* p;
int _p;
};
p = malloc(5);
return(_p);
}
It will fail on the malloc() line because malloc() returns void*. Well,
it's not really an error. It's a violation of C's pointer protocol that
says you must explicitly cast malloc()'s return as (char*) before you assign
it to C. My language will not require that, but only generate a warning.
My IDE will also let you permanently silence warnings that you've already
"signed off on" .... and until the associated source code line changes
again, you'll never see that warning on that line.
But writing to the contents of a pointer to a literal is intentionally
undefined, because there is no guarantee that literals were stored in
writeable memory.
Oh! I misunderstood what you were saying.
I don't see this as undefined behavior. The string literal only conveyed
information at compile time, unless it was used in an expression, at which
case it should not be undefined behavior, but rather it should signal a fault
(on those machines which can signal a fault) and simply conduct the write on
those machines that do not have protected memory and therefore cannot isolate
the inappropriate writes from the appropriate ones.
void foo(char* p)
{
p[0] = '5';
}
char data1[] = "Hi, mom!";
const char data2[] = "Hi, mom!";
int main(int argc, char* argv[])
{
foo("Hi, mom!");
}
Use of the string literal foo("Hi, mom!") should signal a fault.
Use of the string literal used to populate data1 should work fine.
Use of the string literal used to populate data2 should signal a fault.
It is not the string literal that will ever change. It is the thing that
it is populated into. In the case of foo("Hi, mom!") it will have created
an externally unnamed variable in memory somewhere. On machines which have
read-only and read-write memory, it will have gone to read-only. On other
machines it will have gone to read-write memory. In any event, at that
point the string literal no longer exists, but rather the memory location
the compiler assigned for it does exist.
It should not be undefined behavior, but rather defined. There may need to
be exceptions of unimplemented features on certain architectures which cannot
support fault signaling, for example, but the behavior should be defined.
Best regards,
Rick C. Hodgin