LINUX.ORG.RU

Ответ на: комментарий от Crocodoom

Он вроде в памяти хотел, тут без кошек не обойтись.

anonymous
()

класс - это абстракция, в памяти все это выглядит как вызов функции inc(int a), лучше подумай о том как выглядишь ты, почему ты не пошел в спортзал и теперь жирное чмо

anonymous
()
Ответ на: комментарий от anonymous

Ну вот зачем, может он ещё не осилил гуглинг на технические темы.

anonymous
()

как сказали выше - классы ни во что не компилируются, это абстракции. иди читай учебник по крестам, потому что много всяких нюансов, чтобы их на форуме объяснять. если коротко - твой метод inc(int) на самом деле выглядит так: inc(YourClass *, int). Т.е. обычная функция, которая первым параметром принимает указатель на объект твоего класса.

anonymous
()

в ассемблерных кодах

Это еще и от конкретной платформы зависит, кури в сторону thiscall/cdecl и ABI в целом.

anonymous
()

man objdump или idapro или другой дизассемблер возьми

anonymous
()
Ответ на: комментарий от anonymous

Меня в основном с++ на x86 интересует, однажды начал разбирать в дизасемблере, но там и стек и регистры задействовались, решил тогда отложить все до лучших времен.

da17
() автор топика
Ответ на: комментарий от da17

Лучшие времена еще не настали, стек и регистры по прежнему используются. Регистров даже больше стало, а ведь еще есть fpu, mmx, там свои регистры

SR_team ★★★★★
()
Ответ на: комментарий от SR_team

я имел в виду при передаче параметров в ф-ию часть передавалась через регистры, часть через стек

da17
() автор топика
Ответ на: комментарий от da17

это fastcall, либо thiscall. В thiscall через регистры только объект this передается, в x86 это регистр ecx.

SR_team ★★★★★
()
Ответ на: комментарий от da17

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

anonymous
()
Ответ на: комментарий от AlexAT

ну хорош уж меня стукать, чай не на зоне за базаром следить 24 на 7, назвал объект классом, ясно ж, что в виду имел

da17
() автор топика

По разному, если твой метод НЕ виртуальный и нет предков, то вообще никак. Все вызовы этого метода (при этом неважно с экзепляром или нет) при нормальном уровне оптимизации будут просто вызовом функции, а данных в классе нет. То есть такой класс НИКАК в памяти особо и не представлен, просто синтаксичесеский сахар над функцией.

Если класс содержит данные, виртуальные методы, имеет виртуальных предков, области видимости, то там все иначе. Но в каждом случае по разному, единого правила нет.

Dudraug ★★★★★
()
Ответ на: комментарий от anonymous

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

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

ТС спрашивал про объект, но по ошибке обозвал его классом.

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

Т.е. компилятор породит inc(int) вмето inc(*, int) потому что в классе нет полей данных?

anonymous
()
Ответ на: комментарий от anonymous

Т.е. компилятор породит inc(int) вмето inc(*, int) потому что в классе нет полей данных?

Может породить, а может не породить. Тут все зависит от компилятора и конкретной ситуации. Четких правил нет, но сохранять передачу указателей на класс без данных причин нет. Другое дело, что если внутри этой функции идет проверка указателя например на null или передача его(через this) куда-то еще. То тут уже совсем другое дело=) В таком случае выкидывать ничего нельзя само собой.

Dudraug ★★★★★
()
Ответ на: комментарий от anonymous
$ cat mm.cpp 
#include "mm.h"
  void Test::f(int& i)
  {
    i+=1;
  }


$ cat mm.h 
class Test
{
public:
  void f(int& i);
};

$ g++ -O2 -std=c++17 -o mm.o -c mm.cpp
$ objdump -d mm.o 

mm.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <_ZN4Test1fERi>:
   0:	83 06 01             	addl   $0x1,(%rsi)
   3:	c3                   	retq 
Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Но всё таки this передается, хоть и не используется. %rsi это регистр для второго аргумента, а в %rdi наверняка ожидается указатель на объект :)

anonymous
()
Ответ на: комментарий от anonymous

И еще вопрос, я так понимаю что методы класса, при создании объекта представляют из себя список инструкций, который один для всех объектов. Т.е. поля объектов располагаются где-то в памяти, но при вызове метода допустим inc в каждом объекте определяется переход к определенному адрессу, так? Конечно глупо дублировать 200 одинаковые наборов инструкций при создании 200 объектов, но вдруг там как-нибудь еще хитрей и интересней все.

da17
() автор топика
Ответ на: комментарий от da17

глупо дублировать 200 одинаковые наборов инструкций

загугли inline и как оно ускоряет код

заодно и static, чо уж

fluorite ★★★★★
()
Ответ на: комментарий от da17

Т.е. поля объектов располагаются где-то в памяти

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

но при вызове метода допустим inc в каждом объекте определяется переход к определенному адрессу, так?

на самом деле метод ни у какого объекта не вызывается.

т.е. вот этот код:

obj.inc(number);

на самом деле работает вот так:

inc(&obj, number);

anonymous
()
Ответ на: комментарий от anonymous

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

сам ты «первый аргумент», this - это implicit аргумент и в зависимости от abi может быть хоть всегда третьим

anonymous
()
Ответ на: комментарий от da17

ну хорош уж меня стукать, чай не на зоне

чай у тебя на кухне - на зоне чифир

anonymous
()
Ответ на: комментарий от da17

Дык никто и не стукает. Я наоборот свой косяк поправил: спрошено-то про класс, а я объект описал.

AlexAT
()
Ответ на: комментарий от anonymous

cls - это таблица вызовов, адресов процедур, для конкретного класса. никуда не передаётся. может быть как инлайном, так и реально таблицей, зависит от компилятора

AlexAT
()
Ответ на: комментарий от anonymous

Если возможно, то поясняйте для g++, хочу параллельно с вашими объяснениями все палкой потыкать.

da17
() автор топика
Ответ на: комментарий от anonymous

Лор хуже зоны.

Двачую. Там петухов на парашу отправляют, а тут — в модераторы.

anonymous
()
Ответ на: комментарий от anonymous

Смысл простой: как будем полиморфизм при доступе к инстанции объектов наследуемых классов реализовывать?

AlexAT
()
Ответ на: комментарий от anonymous

И да, почему мы говорим не про vtable? У MS - vftable, формируется как раз для virtual.

Вот так выглядит:

class Test1 
{
public:
    virtual int doSomething(const int x)
    {
00B11040  push        ebp  
00B11041  mov         ebp,esp  
        return x + 1;
00B11043  mov         eax,dword ptr [x]  
00B11046  inc         eax  
    }
00B11047  pop         ebp  
00B11048  ret         4  
};

class Test2: public Test1
{
public:
    virtual int doSomething(const int x)
    {
00B11050  push        ebp  
00B11051  mov         ebp,esp  
        return x + 2;
00B11053  mov         eax,dword ptr [x]  
00B11056  add         eax,2  
    }
00B11059  pop         ebp  
00B1105A  ret         4  
};

int doSomething(Test1* cls, const int x)
{
    return cls->doSomething(x);
}

int main()
{
00B11060  push        ebp  
00B11061  mov         ebp,esp  
00B11063  sub         esp,0Ch  
00B11066  mov         eax,dword ptr [__security_cookie (0B13000h)]  
00B1106B  xor         eax,ebp  
00B1106D  mov         dword ptr [ebp-4],eax  
    Test1 t1;
    Test2 t2;
    printf("t1: %i\n", doSomething(&t1, 0));
00B11070  push        0  
00B11072  lea         ecx,[t1]  
00B11075  mov         dword ptr [t1],offset Test1::`vftable' (0B12114h)  
00B1107C  mov         dword ptr [t2],offset Test2::`vftable' (0B1211Ch)  
00B11083  call        Test1::doSomething (0B11040h)  
00B11088  push        eax  
00B11089  push        offset string "t1: %i\n" (0B12100h)  
00B1108E  call        printf (0B11010h)  
    printf("t2: %i\n", doSomething(&t2, 0));
00B11093  mov         eax,dword ptr [t2]  
00B11096  lea         ecx,[t2]  
    Test1 t1;
    Test2 t2;
    printf("t1: %i\n", doSomething(&t1, 0));
00B11099  add         esp,8  
    printf("t2: %i\n", doSomething(&t2, 0));
00B1109C  push        0  
00B1109E  call        dword ptr [eax]  
00B110A0  push        eax  
00B110A1  push        offset string "t2: %i\n" (0B12108h)  
00B110A6  call        printf (0B11010h)  
    return 0;
}
00B110AB  mov         ecx,dword ptr [ebp-4]  
00B110AE  add         esp,8  
00B110B1  xor         ecx,ebp  
00B110B3  xor         eax,eax  
00B110B5  call        __security_check_cookie (0B110BEh)  
00B110BA  mov         esp,ebp  
00B110BC  pop         ebp  
00B110BD  ret  

Исходник:

#include <stdio.h>

class Test1 
{
public:
    virtual int doSomething(const int x)
    {
        return x + 1;
    }
};

class Test2: public Test1
{
public:
    virtual int doSomething(const int x)
    {
        return x + 2;
    }
};

int doSomething(Test1* cls, const int x)
{
    return cls->doSomething(x);
}

int main()
{
    Test1 t1;
    Test2 t2;
    printf("t1: %i\n", doSomething(&t1, 0));
    printf("t2: %i\n", doSomething(&t2, 0));
    return 0;
}

---

00B1109E call dword ptr [eax]

Как раз вызов метода класса из таблицы.

AlexAT
()
Ответ на: комментарий от AlexAT

В случае Test1 компилятор догадался, что можно заинлайнить, и заинлайнил. А вот в случае класса-потомка уже не догадался.

AlexAT
()
Ответ на: комментарий от AlexAT

дружок у тебя в штанишках, а если вы в теме полный ноль, то сиди и помалкивай

#include <stdio.h>

class Test1 
{
public:
    virtual int doSomething(const int x)
    {
        return x + 1;
    }
};

class Test2: public Test1
{
public:
    virtual int doSomething(const int x)
    {
        return x + 2;
    }
};

int doSomething(Test1* cls, const int x)
{
    return cls->doSomething(x);
}

int main()
{
    Test1 t1;
    Test2 t2;
    printf("t1: %i\n", doSomething(&t1, 0));
    printf("t2: %i\n", doSomething(&t2, 0));
    return 0;
}
-O3
Test1::doSomething(int):
        lea     eax, [rsi+1]
        ret
Test2::doSomething(int):
        lea     eax, [rsi+2]
        ret
doSomething(Test1*, int):
        mov     rax, QWORD PTR [rdi]
        jmp     [QWORD PTR [rax]]
.LC0:
        .string "t1: %i\n"
.LC1:
        .string "t2: %i\n"
main:
        sub     rsp, 8
        mov     esi, 1
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        call    printf
        mov     esi, 2
        mov     edi, OFFSET FLAT:.LC1
        xor     eax, eax
        call    printf
        xor     eax, eax
        add     rsp, 8
        ret
так что там куда заинлайнилось щеночек ?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.