arrays - Run-time error using a compound subscripting expression compiled by the MS VS22 C++ compiler - Stack Overflow

I have some obfuscated code specially written to test the subscript operator.From my point of view the

I have some obfuscated code specially written to test the subscript operator.

From my point of view there is used a correct subscripting expression according to the C++ Standard (the so-called sub-expressions E1 and E2 are sequenced. At least in (starting from) the C++17 Standard there is explicitly written: "The expression E1 is sequenced before the expression E2.") . But some compilers as for example MS VS-22 C++ (with supporting the latest C++ Standard) or gcc 8.3 issue a run-time error.

#include <iostream>

int main() 
{
        int a[] = { 1, 2, 3, 4, 5 };

        for (const int *p = a; p != a + sizeof( a ) / sizeof( *a ); ++p)
        {
            std::cout << ( *p++ - 1 )[( --p, a )] << ' ';
        }
        std::cout << '\n';
}

or

import std;

int main() 
{
        int a[] = { 1, 2, 3, 4, 5 };

        for (const int *p = a; p != a + std::size( a ); ++p)
        {
            std::cout << ( *p++ - 1 )[( --p, a )] << ' ';
        }
        std::cout << '\n';
}

Is it a bug of the compilers or do I have missed something important in the C++ Standard relative to subscripting expressions?

I have some obfuscated code specially written to test the subscript operator.

From my point of view there is used a correct subscripting expression according to the C++ Standard (the so-called sub-expressions E1 and E2 are sequenced. At least in (starting from) the C++17 Standard there is explicitly written: "The expression E1 is sequenced before the expression E2.") . But some compilers as for example MS VS-22 C++ (with supporting the latest C++ Standard) or gcc 8.3 issue a run-time error.

#include <iostream>

int main() 
{
        int a[] = { 1, 2, 3, 4, 5 };

        for (const int *p = a; p != a + sizeof( a ) / sizeof( *a ); ++p)
        {
            std::cout << ( *p++ - 1 )[( --p, a )] << ' ';
        }
        std::cout << '\n';
}

or

import std;

int main() 
{
        int a[] = { 1, 2, 3, 4, 5 };

        for (const int *p = a; p != a + std::size( a ); ++p)
        {
            std::cout << ( *p++ - 1 )[( --p, a )] << ' ';
        }
        std::cout << '\n';
}

Is it a bug of the compilers or do I have missed something important in the C++ Standard relative to subscripting expressions?

Share Improve this question edited Mar 12 at 15:54 Vlad from Moscow asked Mar 12 at 13:47 Vlad from MoscowVlad from Moscow 312k27 gold badges201 silver badges353 bronze badges 31
  • 5 What language-revision are you using? C++11, 17, etc? Please add that to your question. Also, include the text of the runtime error, just for completeness. – cigien Commented Mar 12 at 13:49
  • 3 What standard version did you compile against? I believe you need C++17 for this to be guaranteed and MSVS defaults to C++14 unless you say otherwise – NathanOliver Commented Mar 12 at 13:53
  • 1 So you are using /std:c++latest? – NathanOliver Commented Mar 12 at 13:55
  • 1 @Someprogrammerdude I decided to use it along with MS VS22 to check the behavior in the C14. – Vlad from Moscow Commented Mar 12 at 14:03
  • 1 @Someprogrammerdude It seems that there is not mentioned in the C++14 Standard about sequencing the expressions E1 and E2. But in all other newest C++ Standards this is required. So it is strange that the MS VS22 C++ isues a run-time error. – Vlad from Moscow Commented Mar 12 at 14:07
 |  Show 26 more comments

1 Answer 1

Reset to default 1

It is a bug of MS VS compilers.

Starting from the C++17 Standard there were introduced sequences of evaluations of sub-expressions in some expressions with for example shift operators and the same subscipt operator.

From the C++17 Standard (8.2.1 Subscripting):

1 A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall be a glvalue of type “array of T” or a prvalue of type “pointer to T” and the other shall be a prvalue of unscoped enumeration or integral type. The result is of type “T”. The type “T” shall be a completely-defined object type.66 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [ Note: see 8.3 and 8.7 for details of * and + and 11.3.4 for details of arrays. — end note ] , except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise. The expression E1 is sequenced before the expression E2.

However it seems that Microsoft did not make corresponding changes for its compilers relative to the subscript operator.

The subscripting expression in the presented program is evaluated by the MS VS22 C++ compiler starting from the sub-expression in square braces. As result the decremented pointer p in the first iteration of the loop is used to access memory outside the array that invokes undefined behavior.

To prove that it is enough to change the for loop the following way

for (const int *p = a + 1; p != a + std::size( a ); ++p)

though the last element of the array in this case will not be outputted.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744749114a4591484.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信