Порядок параметров в функции обратного вызова

#c #event-handling

#c #обработка событий

Вопрос:

Я наблюдал за этим обсуждением C Con https://www.youtube.com/watch?v=e8SyxB3_mnwamp;t=2933samp;ab_channel=CppCon где было дано что-то вроде следующего кода (https://godbolt.org/z/av4Tbn ):

 struct Handler {
  void handle(int x, int y, int z);

  static void callback0(void *instance, int x, int y, int z) {
    static_cast<Handler *>(instance)->handle(x, y, z);
  }

  static void callback1(int x, int y, int z, void *instance) {
    static_cast<Handler *>(instance)->handle(x, y, z);
  }
};

auto c0 = Handler::callback0;
auto c1 = Handler::callback1;
  

Этот код создает следующую сборку:

 Handler::callback0(void*, int, int, int):
        jmp     Handler::handle(int, int, int)
Handler::callback1(int, int, int, void*):
        mov     r8d, edi
        mov     rdi, rcx
        mov     ecx, edx
        mov     edx, esi
        mov     esi, r8d
        jmp     Handler::handle(int, int, int)
c1:
        .quad   Handler::callback1(int, int, int, void*)
c0:
        .quad   Handler::callback0(void*, int, int, int)
  

Очевидно, что callback0 является предпочтительной версией здесь, но я не понимаю, что происходит «под капотом» в callback1? Может кто-нибудь уточнить?

Ответ №1:

В callback0() , аргументы передаются через регистры процессора в точном порядке, который handle() их ожидает, где instance становится handler this указателем, поэтому нет необходимости переставлять какие-либо значения, следовательно, почему jmp используется само по себе.

В callback1 , аргументы должны быть переставлены в правильные регистры процессора, где handle() их ожидают, прежде чем jmp затем может быть вызван.

Это связано с тем, как работает передача аргументов в различных соглашениях о вызовах.