Каково значение и использование __stdcall?

Это подробно описано с достаточным количеством подробностей самим Гвидо в его сообщении в блоге Order Resolution (включая две предыдущие попытки).

В вашем примере Third() вызовет First.__init__. Python ищет каждый атрибут в родителях класса, поскольку они перечислены слева направо. В этом случае мы ищем __init__. Итак, если вы определите

class Third(First, Second):
    ...

, Python начнет с просмотра First, и, если First не имеет атрибута, тогда он будет смотреть на Second.

Эта ситуация становится более сложной, когда наследование начинает пересекать пути (например, если First унаследовано от Second). Прочтите ссылку выше для более подробной информации, но, в двух словах, Python попытается сохранить порядок, в котором каждый класс появится в списке наследования, начиная с самого дочернего класса.

Так, например, если у вас есть:

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First):
    def __init__(self):
        print "third"

class Fourth(Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print "that's it"

, MRO будет [Fourth, Second, Third, First].

. Кстати: если Python не может найти порядок согласованного метода, он вызовет исключение, вместо этого о возврате к поведению, которое может удивить пользователя.

Отредактировано, чтобы добавить пример двусмысленного MRO:

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        print "third"

Если MF Third будет [First, Second] или [Second, First]? Нет очевидного ожидания, и Python вызовет ошибку:

TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution order (MRO) for bases Second, First

Редактирование: я вижу, что несколько человек утверждают, что в приведенных выше примерах нет вызовов super(), поэтому позвольте мне объяснить: точка примеров чтобы показать, как строится MRO. Они не предназначены для печати «first\nsecond \ third» или что-то еще. Вы можете - и должны, конечно, поиграть с примером, добавить super() звонки, посмотреть, что произойдет, и получить более глубокое понимание модели наследования Python. Но моя цель состоит в том, чтобы держать его простым и показать, как строится MRO. И он построен, как я объяснил:

>>> Fourth.__mro__
(,
 , ,
 ,
 )

70
задан Jean-François Fabre 30 August 2018 в 03:46
поделиться

6 ответов

Все функции в C / C ++ имеют определенное соглашение о вызовах. Суть соглашения о вызовах состоит в том, чтобы установить, как данные передаются между вызывающим и вызываемым объектами и кто отвечает за такие операции, как очистка стека вызовов.

Самые популярные соглашения о вызовах в Windows:

  • __ stdcall , помещает параметры в стек в обратном порядке (справа налево)
  • __ cdecl , помещает параметры в стек в обратном порядке (справа налево)
  • __ clrcall , загружать параметры в стек выражений CLR по порядку (слева направо).
  • __ fastcall , сохраняется в регистрах, затем помещается в стек
  • __ thiscall , Помещен в стек; этот указатель хранится в ECX

. Добавление этого спецификатора к объявлению функции по существу сообщает компилятору, что вы хотите, чтобы эта конкретная функция имела это конкретное соглашение о вызовах.

Соглашения о вызовах описаны здесь

Рэймонд Чен также провел длинную серию статей по истории различных вызовов. соглашения (5 частей), начинающиеся здесь.

61
ответ дан 24 November 2019 в 13:23
поделиться

__ stdcall - это соглашение о вызовах: способ определения того, как параметры передаются в функцию (в стеке или в регистрах) и кто отвечает за очистку после возврата функции (вызывающий или вызываемый).

Раймонд Чен написал блог об основных соглашениях о вызовах x86 , а также там есть хорошая статья CodeProject .

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

7
ответ дан 24 November 2019 в 13:23
поделиться

К сожалению, нет простого ответ на вопрос, когда его использовать, а когда нет.

__ stdcall означает, что аргументы функции помещаются в стек от первого до последнего. В этом отличие от __cdecl, что означает, что аргументы передаются от последнего к первому, а __fastcall,

6
ответ дан 24 November 2019 в 13:23
поделиться

Он определяет соглашение о вызовах для функции. Соглашение о вызовах - это набор правил того, как параметры передаются функции: в каком порядке, для каждого адреса или для каждой копии, кто должен очистить параметры (вызывающий или вызываемый) и т. Д.

3
ответ дан 24 November 2019 в 13:23
поделиться

__ stdcall обозначает соглашение о вызовах (см. этот PDF для некоторых деталей). Это означает, что он определяет, как аргументы функции выталкиваются и извлекаются из стека, и кто за это отвечает.

__ stdcall - это лишь одно из нескольких соглашений о вызовах, которое используется во всем WINAPI. Вы должны использовать его, если вы предоставляете указатели на функции в качестве обратных вызовов для некоторых из этих функций. В общем, вам не нужно указывать какое-либо конкретное соглашение о вызовах в вашем коде, а просто используйте значение по умолчанию компилятора, за исключением случая, указанного выше (обеспечение обратных вызовов для стороннего кода).

2
ответ дан 24 November 2019 в 13:23
поделиться

Это соглашение о вызовах, согласно которому функции WinAPI должны вызываться правильно. Соглашение о вызовах - это набор правил о том, как параметры передаются в функцию и как возвращаемое значение передается из функции.

Если вызывающий и вызываемый код используют разные соглашения, вы столкнетесь с неопределенным поведением (например, ] такой странный сбой ).

Компиляторы C ++ по умолчанию не используют __stdcall - они используют другие соглашения. Поэтому, чтобы вызывать функции WinAPI из C ++, вам необходимо указать, что они используют __stdcall - обычно это делается в файлах заголовков SDK Windoes, и вы также делаете это при объявлении указателей на функции.

1
ответ дан 24 November 2019 в 13:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: