Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
365 views
in Technique[技术] by (71.8m points)

c++ - Is converting between pointer-to-T, array-of-T and pointer-to-array-of-T ever undefined behaviour?

Consider the following code.

#include <stdio.h>
int main() {
 typedef int T;
 T a[] = { 1, 2, 3, 4, 5, 6 };
 T(*pa1)[6] = (T(*)[6])a;
 T(*pa2)[3][2] = (T(*)[3][2])a;
 T(*pa3)[1][2][3] = (T(*)[1][2][3])a;
 T *p = a;
 T *p1 = *pa1;
 //T *p2 = *pa2; //error in c++
 //T *p3 = *pa3; //error in c++
 T *p2 = **pa2;
 T *p3 = ***pa3;
 printf("%p %p %p %p %p %p %p
", a, pa1, pa2, pa3, p, p1, p2, p3);
 printf("%d %d %d %d %d %d %d
", a[5], (*pa1)[5], 
   (*pa2)[2][1], (*pa3)[0][1][2], p[5], p1[5], p2[5], p3[5]);
 return 0;
}

The above code compiles and runs in C, producing the expected results. All the pointer values are the same, as are all the int values. I think the result will be the same for any type T, but int is the easiest to work with.

I confessed to being initially surprised that dereferencing a pointer-to-array yields an identical pointer value, but on reflection I think that is merely the converse of the array-to-pointer decay we know and love.

[EDIT: The commented out lines trigger errors in C++ and warnings in C. I find the C standard vague on this point, but this is not the real question.]

In this question, it was claimed to be Undefined Behaviour, but I can't see it. Am I right?

Code here if you want to see it.


Right after I wrote the above it dawned on me that those errors are because there is only one level of pointer decay in C++. More dereferencing is needed!

 T *p2 = **pa2; //no error in c or c++
 T *p3 = ***pa3; //no error in c or c++

And before I managed to finish this edit, @AntonSavin provided the same answer. I have edited the code to reflect these changes.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The only reason your code compiles in C is that your default compiler setup allows the compiler to implicitly perform some illegal pointer conversions. Formally, this is not allowed by C language. These lines

T *p2 = *pa2;
T *p3 = *pa3;

are ill-formed in C++ and produce constraint violations in C. In casual parlance, these lines are errors in both C and C++ languages.

Any self-respecting C compiler will issue (is actually required to issue) diagnostic messages for these constraint violations. GCC compiler, for one example, will issue "warnings" telling you that pointer types in the above initializations are incompatible. While "warnings" are perfectly sufficient to satisfy standard requirements, if you really want to use GCC compiler's ability to recognize constraint violating C code, you have to run it with -pedantic-errors switch and, preferably, explicitly select standard language version by using -std= switch.

In your experiment, C compiler performed these implicit conversions for you as a non-standard compiler extension. However, the fact that GCC compiler running under ideone front completely suppressed the corresponding warning messages (issued by the standalone GCC compiler even in its default configuration) means that ideone is a broken C compiler. Its diagnostic output cannot be meaningfully relied upon to tell valid C code from invalid one.

As for the conversion itself... It is not undefined behavior to perform this conversion. But it is undefined behavior to access array data through the converted pointers.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...