none
Порядок вычисления аргументов функции в C++/CLI RRS feed

  • Вопрос

  • В C++ порядок вычисления аргументов функции не определен. Однако в C# такой порядок имеется, и аргументы функции вычисляются строго по порядку слева направо.

    Возникает вопрос: установлен ли такой же порядок вычисления аргументов в C++/CLI как в C#?

    Я просматриваю стандарт ECMA 372 по C++/CLI и что-то никак не могу найти, где этот вопрос обговаривался бы.

    Кто-нибудь может указать то место в стандарте ECMA, где об этом говорится, если такое положение вообще существует в стандарте?

    13 октября 2013 г. 19:46

Ответы

  • "Фиксирован ли порядок вычисления аргументов функции в C++/CLI? " - да фиксирован. Как и C# язык C++/CLI является CLI совместимым, а тут в спецификации об этом чётко написано, например стр. 87 пункт 2. Аргументы помещаются в стек слева направо.

    Сделаем содержимое сообщества лучше, вместе!

    15 октября 2013 г. 6:06
    Модератор
  • Порядок расположения аргументов в стандарте CLS – слева направо, это касается и C++/CLI и C#.

    Порядок "вычисления аргументов", как вы выразились, а если быть более точным, то выражений – хаотичный, неупорядоченный. Это не прописано нигде и не будет прописано в будущем. Каждый компилятор реализует его по своему.

    #include "stdafx.h"
    
    using namespace System;
    
    ref class  Test
    {
    public:
    		int A(int a, int b)
    		{
    				return a - b;
    		}
    		int B(int b)
    		{
    				return b;
    		}
    };
    
    int main(array<System::String ^> ^args)
    {
    		Test^ t = gcnew Test;
    		int i = 0;
    		t->A(i++, i + 2 );
    
    		return 0;
    }

    Т.е. никто и никогда не даст вам 100% гарантию того, что первым будет вычислен первый аргумент – i++, а вторым – i + 2. Т.е. результат может быть как: -2, так и 1. Это относится к C# в том числе. Хотя и на данный момент бычисления в основном проходят слева направо, но никаких гарантий нет. Надеюсь, что такой ответ устроит вас.


    Сделаем содержимое сообщества лучше, вместе!

    18 октября 2013 г. 5:28
    Модератор

Все ответы

  • Точно не уверен, но т.к. продукция любого компилятора для .net framework - код на общем промежуточном языке, порядок должен определяться его стандартом.
    14 октября 2013 г. 10:32
  • Ну и отладчик, конечно, может помочь. Поставьте в качестве параметров вызовы функций и, таким образом, определите порядок.
    14 октября 2013 г. 10:36
  • "Порядок вычисления аргументов функции" - не совсем понятно, что под этим вы подразумеваете.

    Сделаем содержимое сообщества лучше, вместе!

    14 октября 2013 г. 11:13
    Модератор
  • Я потому и задал вопрос, что поведение компилятора MS VC++ меняется в зависимости от установки ключа /CLR. То есть для классического C++ компилятор обрабатывает аргументы справа налево. Как только переключаешься на C++/CLR, то порядок обработки аргументов меняется. Кроме того очевидно, что должна быть совместимость по семантике с другими NET языками. Однако нигде в документации я не нашел ответа на вопрос.

    Вот простой пример, демонстрирующий суть вопроса:

    #include "stdafx.h"
    #include <iostream>

    int f( int i ) { std::cout << "f( " << i << " ) is called" << std::endl; return i; }
    void g( int x, int y ) { x + y; }

    int _tmain(int argc, _TCHAR* argv[])
    {
     g( f( 0 ), f( 1 ) );
    }

    Вывод:

    f( 1 ) is called
    f( 0 ) is called

    И

    #include "stdafx.h"

    using namespace System;

    int f( int i ) { Console::WriteLine( "f( {0} ) is called", i ); return i; }

    void g( int x, int y ) { x + y; }

    int main(array<System::String ^> ^args)
    {
        g( f( 0 ), f( 1 ) );

        return 0;
    }

    Вывод:

    f( 0 ) is called
    f( 1 ) is called


    14 октября 2013 г. 11:53
  • Фиксирован ли порядок вычисления аргументов функции в C++/CLI? 

    В C++ такой порядок не фиксирован. С другой стороны, в C# такой порядок фиксирован, то есть аргументы всегда вычисляются слева направо. Возникает вопрос, а что по этому поводу говорит стандарт ECMA по C++/CLI или сама Microsoft?  То есть следует ли C++/CLI в этом вопросе в соответствии со стандартом C++ или же в соответствии со стандартом C#? Этот важный вопрос остается открытым, то есть я нигде не нашел в нормативных документах, как ведет себя C++/CLI по отношению к порядку вычисления аргументов функции..

    14 октября 2013 г. 12:01
  • "Фиксирован ли порядок вычисления аргументов функции в C++/CLI? " - да фиксирован. Как и C# язык C++/CLI является CLI совместимым, а тут в спецификации об этом чётко написано, например стр. 87 пункт 2. Аргументы помещаются в стек слева направо.

    Сделаем содержимое сообщества лучше, вместе!

    15 октября 2013 г. 6:06
    Модератор
  • Увы, ссылку, которую вы предоставили, никакого отношения к C++/CLI не имеет. CLI и C++/CLI - это слвершенно разные вещи. Более того, в той ссылке, на которую вы указали, говорится, что "The CIL provides a “virtual calling convention” that is converted by the JIT compiler into a native calling convention. The JIT compiler determines the optimal native calling convention for the target architecture. This allows the native calling convention to differ from machine to machine, including details of register usage, local variable homes, copying conventions for large call-by-value objects (as well as deciding, based on the target machine, what is considered “large”)."

    О порядке вычисления аргументов функции ( а заметьте, что в C++/CLI функция совсем не обязательно является методом, что я и показал здесь выше в примере) должно быть написано в стандарте C++/CLI. То, что C++/CLI и CLI имеют в своих названиях совпадающие аббревиатуры, ни о чем не говорит. Более того, в C++/CLI может быть смешанный код. Все это должно обговариваться в стандарте C++/CLI.

    15 октября 2013 г. 17:37
  • Более того, порядок занесения аргументов в стек и порядок их вычисления - это очевидно также разные вещи.
    15 октября 2013 г. 17:45
  • Чтобы вы не думали, что все так просто, как вам кажется с вашей ссылкой на CLI, то что говорит C++ и C++/CLI по поводу такого выражения

    int i = 0;

    f( i++, i++ ) + i++; // int f( int, int );

    Является ли оно неопределенным или нет? 

    15 октября 2013 г. 17:56
  • "CLI и C++/CLI - это слвершенно разные вещи." - как же так. Я же не говорю, что это одно и тоже. Но о чём нам говорит аббревиатура CLI, о том что данный язык реализует спецификацию CLS, по другому ни как. А значит компилятор должен генерировать код (CLS совместимый код) работающий в управляемом мире CLR. А в спецификации CLI чётко прописан порядок определения аргументов, слева направо.

    "Более того, порядок занесения аргументов в стек и порядок их вычисления - это очевидно также разные вещи." - а когда они по вашему вычисляются (речь именно о CLR)?

    "Более того, в C++/CLI может быть смешанный код. Все это должно обговариваться в стандарте C++/CLI." - по моему вы сами себя сильно запутываете. Вопрос ставите относительно управляемого кода (а под C++/CLI именно это подразумевается), а потом говорите о смешанном.

    int i = 0;

    f( i++, i++ ) + i++; // int f( int, int ); - всё завист от того где и как вы его используете.



    Сделаем содержимое сообщества лучше, вместе!

    15 октября 2013 г. 18:46
    Модератор
  • Порядок занесения аргументов в стек и порядок их вычисления - это разные вещи. Например, порядок вычисления аргументов в стандарте C++ не специфирован, то есть зависит от реализации компилятора. С другой стороны, порядок занесения аргументов в стек в стандарте C++ вообще не оговорен. Тем не менее существует соглашения (я даже не знаю, в каком документе оно описано), что для C-функций последний аргумент заносится в стек первым. И все компиляторы поддерживают это соглашение. Иначе вы просто не сможете вызывать функции из сторонних библиотек. Или другое соглашение о порядке занесения в стек аргументов в соответствии с вызовами функций на Паскале.

    Как вы теперь, надеюсь, поняли, порядок вычисления аргументов и порядок занесения аргументов в стек - это две разные вещи. Например, MS VC++ вычисляет аргументы справа налево, а, вот, Clang, если я не ошибаюсь, вычисляет аргументы слева направо. Тем не менее оба компилятора заносят аргументы в стек по правилу: последний аргумент заносится в стек первым. Для Windows программ вы можете выбрать соглашение о занесении аргументов с соответствии с языком Паскаль. Тем не менее и в этом случае порядок вычисления значений аргументов стандартом C++ остается не специфицированным.

    Так что то, что CLI заносит аргументы в стек в соответствии с языком Паскаль, ничего не говорит о том, каков порядок вычисления значений аргументов в C++/CLI.

     
    15 октября 2013 г. 21:52
  • Кроме того порядок занесения аргументов в стек никак не определяет, когда применяются побочные эффекты. Я вам показал уже пример. Вопрос именно в том, когда применяются побочные эффекты и в каком порядке. А это связано  в частности с тем, в каком порядке вычисляются аргументы функции.
    15 октября 2013 г. 21:58
  • Я вам про Ивана, вы мне про болвана. :). Не обижайтесь только. Я говрю про управляемый код, а вы про неуправляемый.

    "Порядок занесения аргументов в стек и порядок их вычисления - это разные вещи. Например, порядок вычисления аргументов в стандарте C++ не специфирован, то есть зависит от реализации компилятора. С другой стороны, порядок занесения аргументов в стек в стандарте C++ вообще не оговорен. Тем не менее существует соглашения (я даже не знаю, в каком документе оно описано), что для C-функций последний аргумент заносится в стек первым. И все компиляторы поддерживают это соглашение. Иначе вы просто не сможете вызывать функции из сторонних библиотек. Или другое соглашение о порядке занесения в стек аргументов в соответствии с вызовами функций на Паскале." - опять пример про нативный ко C++.

    "Кроме того порядок занесения аргументов в стек никак не определяет, когда применяются побочные эффекты." - сначала спрашиваете одно, теперь уводите тему в сторону и уже про побочные эффекты.

    "Я вам показал уже пример. Вопрос именно в том, когда применяются побочные эффекты и в каком порядке. А это связано  в частности с тем, в каком порядке вычисляются аргументы функции." - если уже говорить об этом, то тут уже порядок аргументов роли не играет. Всё зависит от конкретно написанного выражения, и как эти выражением компилятор манипулирует и оптимизирует при компиляции. Всё зависит от конкретной реализации компилятора, даже для C#.

    Изначально вы вопрос задали так:

    "Фиксирован ли порядок вычисления аргументов функции в C++/CLI?" - я же ответил и привёл ссылку (стр. 87 пункт 2), вы её внимательно не посмотрели, там написано:

    "The remaining arguments appear on the stack in left-to-right order (that is, the lexically leftmost argument is the lowest on the stack, immediately following the..."

    Мы имеем язык C++/CLI, который реализует спецификацию CLS, значит компилятор управляемого кода C++ должен генерировать CIL (MSIL) код совместно стандартам CLI, что он и делает. А в спецификации CLI чётко прописан порядок : "слева направо". Система виртуального исполнения VES, работает по принципу стековой машины, и порядок тут очень важен, можете убедиться на примере.

    #include "stdafx.h"
    
    using namespace System;
    
    ref class  Test
    {
    public:
    		int A(int a, int b)
    		{
    				return a + b;
    		}
    		int B(int b)
    		{
    				return b;
    		}
    };
    
    int main(array<System::String ^> ^args)
    {
        //Console::WriteLine(L"Hello World");
    		Test^ t = gcnew Test;
    
    		t->A(t->B(0), t->B(1) );
    
        return 0;
    }

    Стек вызовов в CIL

    Вызовы методов вместо аргументов определены в строгом порядке. Мне больше добавить нечего.  А то получается уже флуд и троллинг. Надеюсь на понимание.


    Сделаем содержимое сообщества лучше, вместе!

    16 октября 2013 г. 12:40
    Модератор
  • Я уже вам несколько раз приводил ключевую фразу моего вопроса: порядок вычисления аргументов функции. Я про стек не говорю. Меня интересует как вычисляются переменные в выражениях и в частности в вызовах функций. То есть могу ли я рассчитывать на то, что следующее выражение

    int i = 0;

    f( i++, i++ ) + i++;

    является корректным в C++/CLI и  соответствует выражению

    f( 0, 1 ) + 2;

    16 октября 2013 г. 20:15
  • Очевидно, что в C++ это выражение имеет неопределенное поведение и может соответствовать любым значениям операндов. Этот вопрос должен быть отражен в стандарте C++/CLI, потому что это принципиальная вещь, касающаяся C++.

    16 октября 2013 г. 20:17
  • "Я уже вам несколько раз приводил ключевую фразу моего вопроса: порядок вычисления аргументов функции. Я про стек не говорю. Меня интересует как вычисляются переменные в выражениях и в частности в вызовах функций. То есть могу ли я рассчитывать на то, что следующее выражение" - в самом начале вы не совсем правильно поставили вопрос, поэтому я попросил уточнить. Вы привели следующий код:

    #include "stdafx.h"
    #include <iostream>
    
    int f( int i ) { std::cout << "f( " << i << " ) is called" << std::endl; return i; }
    void g( int x, int y ) { x + y; }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
     g( f( 0 ), f( 1 ) );
    }
    
    Вывод:
    
    f( 1 ) is called
    f( 0 ) is called
    
    И
    
    #include "stdafx.h"
    
    using namespace System;
    
    int f( int i ) { Console::WriteLine( "f( {0} ) is called", i ); return i; }
    
    void g( int x, int y ) { x + y; }
    
    int main(array<System::String ^> ^args)
    {
        g( f( 0 ), f( 1 ) );
    
        return 0;
    }
    и ответ был дан именно на этот вопрос. В самом начале нужно было ставить вопрос относительно побочного эффекта и выражений. :) Так как в этом случае порядок вычисления аргументов не столь критичен, сколько порядок вычисления самого выражения.


    Сделаем содержимое сообщества лучше, вместе!

    17 октября 2013 г. 5:33
    Модератор
  • То есть могу ли я рассчитывать на то, что следующее выражение

    int i = 0;

    f( i++, i++ ) + i++;

    является корректным в C++/CLI и  соответствует выражению

    f( 0, 1 ) + 2;

    Теперь касательно подобных выражений. Выражений с побочным эффектом стоит избегать и не нужно на них полагаться. Так как порядок вычисления выражений определяется конкретной реализацией компилятора и опций компиляции, и может меняться от версии к версии.

    Сделаем содержимое сообщества лучше, вместе!

    17 октября 2013 г. 5:39
    Модератор
  • Это все не является ответом на мой вопрос. Вы постоянно его пытаетесь подменить другим вопросом с самого начала. Вопрос о том, задан ли порядок вычисления значений аргументов функций в C++/CLI, остается открытым. Мне представляется, что это серьезное упущение стандарта, точнее его дефект, так как ничего по этому поводу не говорится в документе по C++/CLI.
    17 октября 2013 г. 16:25
  • Порядок расположения аргументов в стандарте CLS – слева направо, это касается и C++/CLI и C#.

    Порядок "вычисления аргументов", как вы выразились, а если быть более точным, то выражений – хаотичный, неупорядоченный. Это не прописано нигде и не будет прописано в будущем. Каждый компилятор реализует его по своему.

    #include "stdafx.h"
    
    using namespace System;
    
    ref class  Test
    {
    public:
    		int A(int a, int b)
    		{
    				return a - b;
    		}
    		int B(int b)
    		{
    				return b;
    		}
    };
    
    int main(array<System::String ^> ^args)
    {
    		Test^ t = gcnew Test;
    		int i = 0;
    		t->A(i++, i + 2 );
    
    		return 0;
    }

    Т.е. никто и никогда не даст вам 100% гарантию того, что первым будет вычислен первый аргумент – i++, а вторым – i + 2. Т.е. результат может быть как: -2, так и 1. Это относится к C# в том числе. Хотя и на данный момент бычисления в основном проходят слева направо, но никаких гарантий нет. Надеюсь, что такой ответ устроит вас.


    Сделаем содержимое сообщества лучше, вместе!

    18 октября 2013 г. 5:28
    Модератор
  • Все время уходит на то, что вы не в состоянии понять значение фразы "порядок вычисления аргументов", и в  чем состоит разница между порядком вычисления аргументов и порядком их занесения в стек. Я вам уже неоднократно говорил, что это разные вещи. В C# порядок вычисления аргументов и порядок занесения их в стек совпадает. Вы, говоря о C++/CLI, ссылаетесь на C#, хотя нигде, повторяю, нигде не говорится о том, каков порядок вычисления аргументов в C++/CLI. Компилятор Microsoft демонстрирует, что порядок вычисления аргументов в C++/CLI совпадает с порядком вычисления аргументов в C#. То есть никакого "хаотичного неупорядочного" вычисления их нет. Отсюда и мой вопрос, который остался открытым.

    Принимая во внимание, что вам по существу сказать нечего, я склоняюсь к мнению, что просто имеет место дефект стандарта C++/CLI, то есть просто этот вопрос оставили без внимания, хотя на практике следуют положениям стандарта C#.

    31 октября 2013 г. 8:53
  • "Принимая во внимание, что вам по существу сказать нечего, я склоняюсь к мнению, что просто имеет место дефект стандарта C++/CLI, то есть просто этот вопрос оставили без внимания, хотя на практике следуют положениям стандарта C#." - неужели непонятно, что такого в принципе нет. Если нет стандарта, то ни о каком дефекте не может быть и речи. Как захотят, так напишут компилятор. А вам говорят, не полагайтесь на выражения с "побочным эффектом".

    Сделаем содержимое сообщества лучше, вместе!

    31 октября 2013 г. 11:09
    Модератор