Discussion:
Arrays
(too old to reply)
Stefan Ram
2024-09-29 11:33:33 UTC
Permalink
Alright, so I've got a triple whammy of questions coming at me.
It's about this program I've been tinkering with.

#include <stdio.h>
int main()
{ char const abc[] = "abcdefhijklmnopqrstuvwxyz";
char const * const p = abc + 3;
char const( * const def )[] =( char const( * const )[] )p;
printf( "%c\n",( *def )[ -3 ]); }

1st

First off, I'm getting this warning that's throwing me for a loop:

main.c: In function 'main':
main.c:7:32: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
7 | char const( * const def )[] =( char const( * const )[] )p;
| ^

So I'm wondering: How can I dodge this discarding the constness
warning?

2nd

Then I'm hit with another warning:

main.c:7:3: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
7 | char const( * const def )[] =( char const( * const )[] )p;
| ^~~~

What's this warning trying to tell me?

3rd

But the real head-scratcher is that "-3" in the last line.
On paper, we're crunching numbers to get the address of
a spot before the object (the object being "( *def )"),
so technically we're in undefined behavior territory.

But here's the kicker - we know that spot is still chilling in the
"abc" array. Does the language standard have any loopholes that
might save our bacon here and make this not undefined after all?

TIA!
Michael S
2024-09-29 11:45:14 UTC
Permalink
On 29 Sep 2024 11:33:33 GMT
Post by Stefan Ram
Alright, so I've got a triple whammy of questions coming at me.
It's about this program I've been tinkering with.
#include <stdio.h>
int main()
{ char const abc[] = "abcdefhijklmnopqrstuvwxyz";
Are three lines above sufficient to conclude that despite fabulously
extended vocabulary we are dealing with the same Stefan Ram of old?
Scott Lurndal
2024-09-29 18:33:01 UTC
Permalink
Post by Michael S
On 29 Sep 2024 11:33:33 GMT
Post by Stefan Ram
Alright, so I've got a triple whammy of questions coming at me.
It's about this program I've been tinkering with.
#include <stdio.h>
int main()
{ char const abc[] = "abcdefhijklmnopqrstuvwxyz";
Are three lines above sufficient to conclude that despite fabulously
extended vocabulary we are dealing with the same Stefan Ram of old?
I have my doubts. I think someone is playing with an AI that doesn't
realize that Stefan is German.

James Kuyper
2024-09-29 14:04:00 UTC
Permalink
Post by Stefan Ram
Alright, so I've got a triple whammy of questions coming at me.
It's about this program I've been tinkering with.
#include <stdio.h>
int main()
{ char const abc[] = "abcdefhijklmnopqrstuvwxyz";
char const * const p = abc + 3;
char const( * const def )[] =( char const( * const )[] )p;
printf( "%c\n",( *def )[ -3 ]); }
1st
main.c:7:32: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
7 | char const( * const def )[] =( char const( * const )[] )p;
| ^>
So I'm wondering: How can I dodge this discarding the constness
warning?
I'm afraid I can't help you with that.
Post by Stefan Ram
2nd
main.c:7:3: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
7 | char const( * const def )[] =( char const( * const )[] )p;
| ^~~~
What's this warning trying to tell me?
Section 6.5p4 lists the cases where you take a pointer to an object with
a given effective type, convert it to a pointer to a different type, and
dereference that converted pointer with defined behavior. The conversion
you do here isn't one of the ones listed.
That doesn't mean that your code has undefined behavior. You only access
the memory using (*def)[-3], which is an lvalue of character type, which
is not only the same as the effective type of that memory, but is also
one of the options listed in 6.5p4. However, in general, the result of
the conversion could be used in ways that do violate 6.5p4. I don't see
how you could do so in this case, because you can't use a pointer to an
array type to directly access the memory - you have to subscript it to
do so. There's a reason why this is a warning rather than a fatal error.
Post by Stefan Ram
3rd
But the real head-scratcher is that "-3" in the last line.
On paper, we're crunching numbers to get the address of
a spot before the object (the object being "( *def )"),
so technically we're in undefined behavior territory.
But here's the kicker - we know that spot is still chilling in the
"abc" array. Does the language standard have any loopholes that
might save our bacon here and make this not undefined after all?
(*def)[-3] is defined as equivalent to *(*def - 3), so this involves
subtracting an integer value from a pointer value. The relevant rules are:

"If the pointer operand points to an element of an array object, and the
array is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integer expression.
In other words, if the expression P points to the i-th element of an
array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N
(where N has the value n) point to, respectively, the i + n-th and i −
n-th elements of the array object, provided they exist. Moreover, if the
expression P points to the last element of an array object, the
expression (P)+1 points one past the last element of the array object,
and if the expression Q points one past the last element of an array
object, the expression (Q)-1 points to the last element of the array
object. If the pointer operand and the result do not point to elements
of the same array object or one past the last element of the array
object, the behavior is undefined." (6.5.6p9)

Note that the limits are based solely upon the array containing the
element that the pointer points at; how the pointer itself is declared
is not relevant. In this case, you can safely move that pointer as far
back as the "a" in abc[], and as far forward as the the null character
at the end of abc, and access the pointed-at character. You can also
advance it one past the null character, but the resulting pointer value
cannot be dereferenced. It can be used for pointer comparisons, which is
the single most common use of one-past-the-end pointer values.
Kaz Kylheku
2024-09-29 16:11:08 UTC
Permalink
Post by Stefan Ram
Alright, so I've got a triple whammy of questions coming at me.
It's about this program I've been tinkering with.
#include <stdio.h>
int main()
{ char const abc[] = "abcdefhijklmnopqrstuvwxyz";
char const * const p = abc + 3;
char const( * const def )[] =( char const( * const )[] )p;
^^^^^^^^^^^^^^^^^^^^^^^^^
]
This is a const pointer to an array (of unknown size) to const char.
Post by Stefan Ram
printf( "%c\n",( *def )[ -3 ]); }
1st
main.c:7:32: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
7 | char const( * const def )[] =( char const( * const )[] )p;
The problem is that def is a pointer to an array of const char.

The const char elements are const qualified, but the array type is not!

That's why a qualifier is being stripped in the cast.
Post by Stefan Ram
So I'm wondering: How can I dodge this discarding the constness
warning?
I would say, don't work with pointers to arrays.

There is no way to declare a const array in declarator syntax.
You must create a typedef name N for the array type and then
refer to it as const N.
Post by Stefan Ram
2nd
main.c:7:3: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
7 | char const( * const def )[] =( char const( * const )[] )p;
| ^~~~
What's this warning trying to tell me?
That you're banging your head against array-pointer-const corner cases
in the C language.
--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @***@mstdn.ca
Loading...