Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
802 / 529 / 157
Регистрация: 27.01.2015
Сообщений: 3,017
Записей в блоге: 1
1

Преобразование указателей на функции

25.12.2015, 19:38. Показов 1354. Ответов 10
Метки нет (Все метки)

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

Итак, к делу. Вопрос скорее будет адресован на опытных юзверей. Можете объяснить результат работы программы?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <windows.h>
using namespace std;
 
int func()
{
    return 3;
}
 
int main(void)
{
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    void* x(func);
    cout << reinterpret_cast<double(*)()>(x)() << endl;
    system("pause");
    return 0;
}
На выходе получаем:
-nan(ind)
Хотел бы просто у грамотных поинтересоваться, что же происходит в глубинах при вызове функции посредством "кривого" указателя?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.12.2015, 19:38
Ответы с готовыми решениями:

Почему в сортировке указателей на объекты в вызове функции используются адреса объектов, а не указателей?
Доброго времени суток! Рассматриваю пример (из Лафоре) сортировки массива указателей на объекты,...

Создать специфицированный шаблон функции, принимающей массив указателей на char и количество самих указателей
Задача: создать специфицированный шаблон функции, принимающей массив указателей на char и...

Преобразование указателей
Выводит дерево вместо адреса int x = 5; int *p; p = &amp;x; cout &lt;&lt; p &lt;&lt; endl; ...

Преобразование указателей
Люди добрые, прокомментируйте поЖалуйста. #include &lt;iostream&gt; using namespace std; void...

10
15352 / 8300 / 2014
Регистрация: 30.01.2014
Сообщений: 14,171
25.12.2015, 19:48 2
Лучший ответ Сообщение было отмечено Ferrari F1 как решение

Решение

Цитата Сообщение от Ferrari F1 Посмотреть сообщение
что же происходит в глубинах при вызове функции посредством "кривого" указателя?
Для Intel (x86) архитектуры:
int возвращается через регистр EAX, double (обычно) - через регистры FPU. Скастив пойнтнер на функцию ты заставил вызывающий код считать, что: "результат работы забираем из регистров FPU". Однако на самом деле там сейчас лежит что-то непотребное. Тройка благополучно помещена была в EAX, но ее оттуда никто не забирал.
2
1506 / 825 / 175
Регистрация: 05.12.2015
Сообщений: 2,455
26.12.2015, 00:40 3
Цитата Сообщение от DrOffset Посмотреть сообщение
(обычно) - через регистры FPU
Точнее через вершину его стека и всегда. Причем все компиляторы давно уже считают flop-ы через sse, поэтому в x86_64 возврат идет через xmm. А в x86 приходится перед возвратом делать fld.
1
15352 / 8300 / 2014
Регистрация: 30.01.2014
Сообщений: 14,171
26.12.2015, 02:39 4
Цитата Сообщение от avgoor Посмотреть сообщение
и всегда
Все-таки это зависит от настроек компилятора.
Вот например Open Watcom в режиме stack-based calling возвращает double в двух регистрах (eax:edx).
0
1506 / 825 / 175
Регистрация: 05.12.2015
Сообщений: 2,455
26.12.2015, 13:45 5
Цитата Сообщение от DrOffset Посмотреть сообщение
Все-таки это зависит от настроек компилятора.
Вот например Open Watcom в режиме stack-based calling возвращает double в двух регистрах (eax:edx)
Не слышал.
Вообще странно, учитывая что разрядность FPU (10 байт) больше разрядности double. И единственный способ сохранить всю информацию передавать - через FPU.
0
15352 / 8300 / 2014
Регистрация: 30.01.2014
Сообщений: 14,171
26.12.2015, 14:03 6
Цитата Сообщение от avgoor Посмотреть сообщение
Не слышал.
Мне приходилось работать. Правда уже давно.
Цитата Сообщение от avgoor Посмотреть сообщение
Вообще странно
Вот такой код:
C++
1
2
3
4
double test(double с)
{
    return c;
}
Дает вот такой ассемблер (распечатка встроенного дизассемблера):
Assembler
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
double test(double c)
0000                          double near test( double ):
0000    53                        push        ebx 
0001    56                        push        esi 
0002    57                        push        edi 
0003    55                        push        ebp 
0004    89 E5                     mov         ebp,esp 
0006    81 EC 08 00 00 00         sub         esp,0x00000008 
 
{
    return c;
000C                          L$1:
000C    8B 45 14                  mov         eax,dword ptr 0x14[ebp] 
000F    89 45 F8                  mov         dword ptr -0x8[ebp],eax 
0012    8B 45 18                  mov         eax,dword ptr 0x18[ebp] 
0015    89 45 FC                  mov         dword ptr -0x4[ebp],eax 
 
}
0018    8B 45 F8                  mov         eax,dword ptr -0x8[ebp] 
001B    8B 55 FC                  mov         edx,dword ptr -0x4[ebp] 
001E                          L$2:
001E    89 EC                     mov         esp,ebp 
0020    5D                        pop         ebp 
0021    5F                        pop         edi 
0022    5E                        pop         esi 
0023    5B                        pop         ebx 
0024    C3                        ret
Они исходят из того, что разрядность double 8 байт.
0
1506 / 825 / 175
Регистрация: 05.12.2015
Сообщений: 2,455
26.12.2015, 14:06 7
Цитата Сообщение от DrOffset Посмотреть сообщение
C++
1
2
3
double test(double с)
{
 return c;
}
А можешь это откомпилить:
C++
1
2
3
4
double test(double с)
{
 return c+1;
}
Интересно стало.
0
15352 / 8300 / 2014
Регистрация: 30.01.2014
Сообщений: 14,171
26.12.2015, 14:11 8
Цитата Сообщение от avgoor Посмотреть сообщение
А можешь это откомпилить
Assembler
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
double test(double c)
0000                          double near test( double ):
0000    53                        push        ebx 
0001    56                        push        esi 
0002    57                        push        edi 
0003    55                        push        ebp 
0004    89 E5                     mov         ebp,esp 
0006    81 EC 08 00 00 00         sub         esp,0x00000008 
 
{
    return c + 1;
000C                          L$1:
000C    D9 E8                     fld1        
000E    DC 45 14                  fadd        qword ptr 0x14[ebp] 
0011    DD 5D F8                  fstp        qword ptr -0x8[ebp] 
 
}
0014    8B 45 F8                  mov         eax,dword ptr -0x8[ebp] 
0017    8B 55 FC                  mov         edx,dword ptr -0x4[ebp] 
001A                          L$2:
001A    89 EC                     mov         esp,ebp 
001C    5D                        pop         ebp 
001D    5F                        pop         edi 
001E    5E                        pop         esi 
001F    5B                        pop         ebx 
0020    C3                        ret
Собственно FPU используется при расчете, но при возврате все равно результат скидывают в eax:edx.
0
1506 / 825 / 175
Регистрация: 05.12.2015
Сообщений: 2,455
26.12.2015, 14:21 9
Да, интересное решение.
Assembler
1
2
3
0011    DD 5D F8                  fstp        qword ptr -0x8[ebp] 
0014    8B 45 F8                  mov         eax,dword ptr -0x8[ebp] 
0017    8B 55 FC                  mov         edx,dword ptr -0x4[ebp]
Добавлено через 7 минут
В смысле: на хрена так делать? Единственное, что в голову приходило - программная эмуляция отсутствующего x87. Но нет.
0
15352 / 8300 / 2014
Регистрация: 30.01.2014
Сообщений: 14,171
26.12.2015, 14:44 10
Цитата Сообщение от avgoor Посмотреть сообщение
на хрена так делать?
Watcom вообще отличался большой гибкостью в этих вещах. Обычный способ возврата floating point там тоже поддерживается.
Там даже была возможность использовать свою собственную calling convention (#pragma aux), если очень хочется.

Добавлено через 5 минут
А, ну и к вопросу "зачем так делать". Такая calling convention использовалась в Novell Netware, под которую Watcom тоже умеет собирать приложения.
0
1506 / 825 / 175
Регистрация: 05.12.2015
Сообщений: 2,455
26.12.2015, 15:07 11
Цитата Сообщение от DrOffset Посмотреть сообщение
Такая calling convention использовалась в Novell Netware
Тогда понятно. Она вообще мимо меня прошла.

Добавлено через 9 минут
Ну то есть я знал, конечно, что такая хрень есть, но первая моя сетка была на TCP/IP, а IPX и иже с ним я только издалека видел. Да она в общем и подыхать уже начала.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.12.2015, 15:07

Задачка на понимание указателей, преобразование типов
Написать функцию, принимающую вещественное число типа float, превращающую его в целое типа int с...

Нюансы арифметики указателей: преобразование к char* при вычислении сдвига
Добрый день! Вчера, при чтении темы возник вопрос различия между указателями и массивами. В теме...

Различные функции, для которых можно создать массив указателей на функции
Придумайте не менее 3-х различных функций, для которых можно создать массив указателей на функции.

Преобразование указателей СИ
Увидел в программе вот такую строчку: #defyme SPI_DR8 *(uint8_t *)0x4001300C ... uint8_t...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru