Форум программистов, компьютерный форум, киберфорум
Visual C++
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.71/35: Рейтинг темы: голосов - 35, средняя оценка - 4.71
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
1

Обращение к переменным объекта с использованием указателя this из inline assembler

21.09.2009, 22:15. Показов 6660. Ответов 74
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Мне нужно написать класс на С++ с учетом возможности ввода количества столбцов и строк матрицы. Матрица должна размещаться в динамической памяти. Переменные указателя на матрицу и размеров матрицы должны быть нестатическими членами класса. Обращение к переменным должно осуществляться с использованием указателя this без использования оператора разыменования указателя (->). Вся выделяемая память в программе должна быть освобождена перед выходом.
Я сделал так, но пишет ошибки:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "stdafx.h"
#include <iostream>
#include "conio.h"
using namespace std;
#include <Windows.H>
 
class Matrix {
private:
int* rows; //пока только строки
 
public:
//Circle () ; недописаный конструктор
void SetRows(int* x) 
{
if ((*x>0)&&(*x<20))  (*this).rows=x;
return;
}
 
int GetRows(void) 
{
return *rows;
}
 
//~Circle () ; недописаный деструктор
};
 
int main()
{
    int* rows=new int;
    
    Matrix t;
 
    t.SetRows(rows);
    cout<<t.GetRows()<<endl;
    return _getch();
}
Помогите исправить.

Добавлено через 38 минут
Вот так получилось. А как массив задать?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include "stdafx.h"
#include <iostream>
#include "conio.h"
using namespace std;
#include <Windows.H>
 
class Matrix {
private:
int* rows;
int* cols;
 
public:
//Matrix(void) недописанный конструктор
 
void SetRows(int* x) 
{
if ((*x>0)&&(*x<20))  (*this).rows=x;
return;
}
 
int GetRows(void) 
{
return *rows;
}
 
void SetCols(int* y) 
{
if ((*y>0)&&(*y<20))  (*this).cols=y;
return;
}
 
int GetCols(void) 
{
return *cols;
}
 
~Matrix(void) //деструктор
{
delete rows;
delete cols;
}
};
 
int main()
{
    int* rows=new int;
    int* cols=new int;
 
    *rows=5;//установим размер матрицы
    *cols=4;
 
    Matrix t;
 
    t.SetRows(rows);
    t.SetCols(cols);
    cout<<t.GetRows()<<" "<<t.GetCols()<<endl;
    return _getch();
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.09.2009, 22:15
Ответы с готовыми решениями:

GCC Inline Assembly перевести в Visual Studio Inline Assembler
Здравствуйте. Есть код на GCC Inline Assembly и его нужно перевести в Visual Studio Inline...

inline assembler в СИ
Доброго! каким образом можно связать внешную переменную и встроенный ассмблер в Си? чтоб было...

Преобразование кода без указателя в код с использованием указателя
Правильно ли выполнил? Исходный код без указателя #include &lt;iostream&gt; #include &lt;cstdlib&gt;...

Inline assembler mingw
Добрый вечер ув. пользователи форума. Возникла проблема с ассемблером, и его реализацией в mingw....

74
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 19:31 21
Author24 — интернет-сервис помощи студентам
galileopro, push надо сделать один раз вне цикла. У тебя метка выше и он на каждом проходе делает push. Нужно или вынести из цикла, т.е сделать push до метки lp2, или где-то в цикле делать pop,только это вроде нафиг не надо.

Добавлено через 8 минут
Да,по поводу не той ячейки - мы не учли,размер инта, нужно умножить содержимое ecx на 4( или сдвинуть влево на 2..). И для esi то же самое верно.Ща мануал посмотрю))
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 19:36  [ТС] 22
Я попробовал "в лоб"
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class Matrix {
private:
int rows;
int cols;
int vect;
int** MyMatrix;   //указатель на начало массива
int* MyVector;   //указатель на начало результирующего вектора
 
public:
Matrix(void)
{
 rows =7;
 cols =5;
 vect =max(cols,rows)/2+1;
MyVector = new int[vect];
 
MyMatrix = new int*[cols];
for(int i=0;i<rows;i++) 
MyMatrix[i]= new int[cols];
}
 
void SetRows(int x) 
{
if ((x>0)&&(x<20))rows=x;
return;
}
 
int GetRows(void) 
{
return rows;
}
 
void SetCols(int y) 
{
if ((y>0)&&(y<20)) cols=y;
return;
}
 
int GetCols(void) 
{
return cols;
}
 
void InputRandomMatrix(void)
{
srand(time(NULL));
for(int i=0;i<rows;i++)
    for(int j=0;j<cols;j++) 
        MyMatrix[i][j]=rand()%20;
}
 
void Calculate(void)
{
__asm   
{
    mov esi, rows
    mov edx, 0  ;первый столбец нечетный
    mov ebx, 0
l2:         
cmp edx, 0 ;будем проверять столбец массива на нечетность
je lp1
jmp m1;
lp1:
mov ecx, cols
xor eax, eax ;быстрый способ очистки регистра ax 
mov ebx, this
lp2:
add eax, [ebx].MyMatrix[ecx][2] //суммируем єлементы 2 столбца
loop lp2               
mov [ebx].MyVector[0], eax //добавляем результат в выходной вектор
m1:
not edx ;столбец поменял четность
dec esi ;переходим к следующему столбцу
cmp esi, 0  
ja l2     
}
return;
}
 
int GetVector(int CoordForVector) 
{
return MyVector[CoordForVector];
}
 
int GetVectorSize(void) 
{
return vect;
}
 
~Matrix(void) //деструктор
{
delete MyMatrix;
delete MyVector;
}
};
 
int main()
{
    Matrix t;
    t.InputRandomMatrix();
    t.Calculate();
    for(int j=0;j<t.GetVectorSize();j++)
    cout<<t.GetVector(j)<<endl;
    return _getch();
}
Но на єкран ничего не вывело. Спасибо. Я там с регистрами как-нибудь разберусь, уже ты мне все растолковал. Но вот в этом случае хочется, чтоб вывел результат, а потом я уже домучаю эту прогу. Тут уже я все упростил, оно просто элементы 2 столбца суммирует. Но не выводит ничего. Хоть 0 бы вывело(
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 19:42 23
У тебя там бесконечный цикл похоже.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 19:48  [ТС] 24
Вот еще упростил.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Calculate(void)
{
__asm   
{
    mov esi, rows
    mov edx, 0  ;первый столбец нечетный
    mov ebx, 0
l2:         
mov ecx, cols
xor eax, eax ;быстрый способ очистки регистра ax 
mov ebx, this
lp2:
add eax, [ebx].MyMatrix[ecx][2] //суммируем єлементы 2 столбца
loop lp2               
mov [ebx].MyVector[0], eax //добавляем результат в выходной вектор
dec esi //переходим к следующему столбцу
cmp esi, 0  //если все столбцы перебрали, то выход
ja l2     
}
return;
}
Где тут бесконечный цикл?
loop lp2 уменьшает постепенно регистр ecx, пока он не станет 0
dec esi //переходим к следующему столбцу - тоже вічитает, пока не занулится.
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 19:53 25
C++
1
mov esi, rows
После выполнения этой строки у меня в регистре esi ноль. В конце dec уменьшал его на 1 и получал максимальное положительное число.Короче,цикл не бесконечный но очень длинный вышел
Зато если сделать через this, как с MyMatrix
C++
1
2
mov ebx, this
mov esi, [ebx].rows
Будет как надо. И так же нужно загружать cols в регистр.

Я поправил,он вылетает с ошибкой,но хоть не циклится
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 20:03  [ТС] 26
Вот так переписал
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void Calculate(void)
{
__asm   
{
    mov ebx, this
    mov esi, [ebx].rows
l2:         
mov ecx, [ebx].cols
xor eax, eax ;быстрый способ очистки регистра ax 
lp2:
add eax, [ebx].MyMatrix[ecx][2] //суммируем єлементы 2 столбца
loop lp2               
mov [ebx].MyVector[0], eax //добавляем результат в выходной вектор
dec esi //переходим к следующему столбцу
cmp esi, 0  //если все столбцы перебрали, то выход
ja l2     
}
return;
}
 
int GetVector(int CoordForVector) 
{
return MyVector[CoordForVector];
}
...
};
 
int main()
{
    Matrix t;
    t.InputRandomMatrix();
           t.Calculate();
    cout<<t.GetVector(0)<<endl;
    return _getch();
Вроде процедура ассемблерная работает, но оно вылетает с ошибкой в строке
C++
1
return MyVector[CoordForVector];
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 20:14 27
galileopro, причина такая.
C++
1
mov [ebx].MyVector[0], eax //добавляем результат в выходной вектор
Нельзя напрямую так писать. Потому что MyVector - это указатель и ты записываешь не в массив, а на место указателя, добавляя к адресу ноль,или не ноль - не важно,все равно напишется не туда. Именно поэтому нужно сначала загрузить значение(!) MyVector в регистр,а после этого писать как-то так :
mov [eax][смещение],что-то там.eax для примера,можно любой общего назначения. Причем адресовать сразу по ячейке памяти нельзя.

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

Обращение к переменным объекта с использованием указателя this из inline assembler


Другими словами еще раз - тебе нужно адресовать по ячейке памяти,там лежит адрес массива,который тебе выдал new когда ты создавал его. [ebx].MyVector[0] просто берет адрес этой ячейки и добавляет 0. А нужно взять тот адрес,который внутри записан и добавить к нему ноль. Вот разница.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 20:26  [ТС] 28
Примерно так?
Assembler
1
2
mov edx, [ebx].MyVector[0]
mov [eax][8], edx
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 20:32 29
galileopro, ты там регистры кажется перепутал. Но в общем я понял,что ты понял
MyVector можно без индекса. В ассемблере индекс не делает разименование, еще одна формулировка предыдущего поста. Т.е в си применяя к указателю в памяти [] ты попадаешь на массив,а в асме - просто смещаешься куда-то дальше

C++
1
2
mov eax,[ebx].MyVector
mov [eax][8], edx
0
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 20:39  [ТС] 30
Ясно. А почему
Эта операция
Assembler
1
add eax, [ebx].MyMatrix[ecx][2]
помещает в
eax = 3435973632 если ecx=5 при этом?
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 20:45 31
galileopro, та же причина. Более того,тебе придется несколько раз обновлять регистр с указателем. В классе матрица представлена одним единственным указателем - он указывает на массив из указателей(вне класса,в динамической памяти), а они каждый на свой "вектор"(см. схему (= ). Чтобы добраться до значения тебе нужно :
C++
1
2
3
4
5
6
mov eax,[ebx].MyMatrix // Залить значение [ebx].MyMatrix в какой-нибудь регистр Пусть eax
mov eax,[eax][ecx] // [eax] - это значит "адрес,который лежит в eax".Это фактически 
                               //разыменование указателя. Тут мы получили указатель на нужную
                               // строку и уложили его опять таки в eax
mov eax,[eax][2] // Тут из вектора мы выбираем нужный элемент.
                            // Теперь в eax значение MyMatrix[ecx][2] в понимании C
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 20:58  [ТС] 32
Все значения должны быть от 0 до 20 где-то

Добавлено через 7 минут
Спасибо я понял. Вот переделал, но он вілетает.(
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Calculate(void)
{
__asm   
{
    mov ebx, this
    mov esi, [ebx].rows
l2:         
mov ecx, [ebx].cols
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][ecx]
mov eax,[eax][2]
mov edx, [ebx].MyVector[0]
mov [edx][8], eax
dec esi //переходим к следующему столбцу
cmp esi, 0  //если все столбцы перебрали, то выход
ja l2     
}
return;
}
Ошибка в строке
C++
1
mov eax,[eax][2]
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 21:02 33
galileopro, забыл умножить ecx на 4.Асм за размером не следит,он с байтами работает. Т.е читается какой-то левый указатель из,скажем, трех байт одного и одного байта следующего за ним К тому же, если ecx == cols, то мы вылезем за границу,т.к массивы нумеруются с нуля.

Добавлено через 26 секунд
Я отойду минут на сорок.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 21:24  [ТС] 34
Вот слава Богу заработало
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// лаба6.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <iostream>
#include "conio.h"
#include <ctime>
#include <Windows.H>
using namespace std;
 
class Matrix {
private:
int rows;
int cols;
int vect;
int** MyMatrix;   //указатель на начало массива
int* MyVector;   //указатель на начало результирующего вектора
 
public:
Matrix(void)
{
 rows =7;
 cols =5;
 vect =max(cols,rows)/2+1;
MyVector = new int[vect];
 
MyMatrix = new int*[cols];
for(int i=0;i<rows;i++) 
MyMatrix[i]= new int[cols];
}
 
void SetRows(int x) 
{
if ((x>0)&&(x<20))rows=x;
return;
}
 
int GetRows(void) 
{
return rows;
}
 
void SetCols(int y) 
{
if ((y>0)&&(y<20)) cols=y;
return;
}
 
int GetCols(void) 
{
return cols;
}
 
void InputRandomMatrix(void)
{
srand(time(NULL));
for(int i=0;i<rows;i++)
    for(int j=0;j<cols;j++) 
        MyMatrix[i][j]=rand()%20;
}
 
void Calculate(void)
{
__asm   
{
mov ebx, this
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][4]
mov eax,[eax][2]
mov edx, [ebx].MyVector[0]
shr eax, 16
mov [edx][0], eax    
}
return;
}
 
int GetVector(int CoordForVector) 
{
return MyVector[CoordForVector];
}
 
int GetVectorSize(void) 
{
return vect;
}
 
~Matrix(void) //деструктор
{
delete MyMatrix;
delete MyVector;
}
};
 
int main()
{
    Matrix t;
    t.InputRandomMatrix();
    t.Calculate();
    cout<<t.GetVector(0)<<endl;
    return _getch();
}
Только вот непойму, почему оно не работает без
C++
1
2
3
4
5
6
7
8
void Calculate(void)
{
__asm   
{
...
shr eax, 16
...   
}
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 21:53 35
mov eax,[eax][2] - это середина ячейки из 4-х байт.Умножай все индексы на 4 >_<

Добавлено через 1 минуту
И у тебя очистка памяти неправильная
delete MyMatrix;

Нужно сначала удалить каждую строку матрицы, сколько раз вызвал new столько же раз вызывай delete. т.е циклом сначала все строки, MyMatrix[i],а потом саму MyMatrix
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 22:01  [ТС] 36
Легко сказать умножай все на 4. Для єтого надо сначала засунуть множитель в eax, затем умножить, потом опять поместить в исходный регистр и восстановить eax. Это жуткий гемор.
Хотя можно
Assembler
1
shr нужный регистр, 2
Да?

Добавлено через 2 минуты
C++
1
2
3
4
5
6
7
~Matrix(void) //деструктор
{
for(int i=0;i<rows;i++) 
delete MyMatrix[i];
delete MyMatrix;
delete MyVector;
}
ЗАработало с первого раза) Спасибо
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 22:16 37
galileopro, нужно влево сдвигать,вроде shl
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
22.09.2009, 22:37  [ТС] 38
К сожалению
Assembler
1
2
3
4
5
6
7
8
mov ebx, this
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][4]
mov eax,[eax][2]
mov edx, [ebx].MyVector[0]
shl eax, 2
mov [edx][0], eax
Выводит -1873232....
C++
1
2
3
4
5
6
7
8
9
mov ebx, this
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][4]
mov eax,[eax][2]
mov edx, [ebx].MyVector[0]
mov ecx, 4
mul ecx
mov [edx][0], eax
Вылетает.
Работает нормально только
C++
1
2
3
4
5
6
7
8
9
10
11
__asm   
{
mov ebx, this
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][4]
mov eax,[eax][2]
mov edx, [ebx].MyVector[0]
shr eax, 16
mov [edx][0], eax    
}
Может там не по середине значение находится? А вообще неважно, я буду теперь shr <registr>, 16 .зать и всех делов. Спасибо за помощь.
0
Эксперт С++
2255 / 770 / 25
Регистрация: 27.05.2008
Сообщений: 1,496
22.09.2009, 22:58 39
C++
1
2
3
mov ecx, 4
mul ecx
mov [edx][0], eax
Я вообще логику этих строк не понял,и я не про них говорил

А сдвигом вправо eax перед тем как его занести ты делишь то,что прочитал на 2^16 и получаешь чето маленькое,чего и хотел,но это вообще левая цифра.
Я говорил про эту строку
C++
1
mov eax,[eax][2]
Ты запихиваешь в eax середину одной цифры и середину другой. Вот и получаешь мусор.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
23.09.2009, 21:24  [ТС] 40
Цитата Сообщение от XuTPbIu_MuHTAu Посмотреть сообщение
А сдвигом вправо eax перед тем как его занести ты делишь то,что прочитал на 2^16 и получаешь чето маленькое,чего и хотел,но это вообще левая цифра.
Нет. Это не левая цифра. Попробуй этот код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
void InputRandomMatrix(void)
{
for(int i=0;i<rows;i++)
    for(int j=0;j<cols;j++) 
        MyMatrix[i][j]=19;
}
 
void Calculate(void)
{
__asm   
{
mov ebx, this
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][4]
mov eax,[eax][2]
mov edx, [ebx].MyVector[0]
shr eax, 16
mov [edx][0], eax    
}
return;
}
...
И выведет 19. Заполнишь матрицу другими числами и выведет их.
Я что-то никак не пойму, что там на 4 умножать?
Он после такого вылетает
C++
1
2
3
4
5
6
7
8
9
mov ebx, this
xor eax, eax ;быстрый способ очистки регистра ax 
mov eax,[ebx].MyMatrix 
mov eax,[eax][4]
shr eax, 4
mov eax,[eax][2]
shr eax, 4
mov edx, [ebx].MyVector[0]
mov [edx][0], eax
0
23.09.2009, 21:24
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.09.2009, 21:24
Помогаю со студенческими работами здесь

Inline Assembler & C++
int main(int argc, char *argv) { perevod(); cout&lt;&lt;&quot;Type Esc to Escape \n&quot;; __asm ...

написать программу движущийся графический объект с двумя способоми с использованием статического объекта и с использованием динамического объекта
Движение закрашенного прямоугольника по треугольному контуру с изменением цвета при изменении...

inline assembler VS чтение по указателю
Доброе время суток. Задача состоит в чтении 1 байта по адресу указателя. Проблема с пониманием,...

Как исправить код? / Inline assembler
#include &lt;stdio.h&gt; int main(int argc, char** argv ) { int aa; int bb; aa = 42; bb =...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru