MyTetra Share
Делитесь знаниями!
Как получить адрес функции в языке C++
Время создания: 18.02.2022 11:47
Текстовые метки: язык, Си++, C++, указатель, функция, адрес
Раздел: Компьютер - Программирование - Язык C++ (Си++)
Запись: xintrea/mytetra_syncro/master/base/16451740798lx4rucxsx/text.html на raw.github.com

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



#include <iostream>

#include <stdio.h>


// Код функции func() находится в ячейке, например, памяти 64C18F7249B0

int func()

{

return 7;

}

int main()

{

    // C-стиль получения адреса в виде числа,

// такую запись можно использовать и в C++

unsigned long a = reinterpret_cast<unsigned long>( func );
   printf("a = %lX\n", a);


// C++ - стиль вывода в консоль напрямую

std::cout << func;


// C++ - стиль вывода в консоль через приведение к типу void*

std::cout << reinterpret_cast<void*>(func);

return 0;

}



В консоль будет выведено:



a = 64C18F7249B0

1

0x64C18F7249B0


Получение адреса работает одинаково для Си и Си++. А вот вывод значения указателя на функцию в стандартный поток для Си++ имеет особенности. Если просто попыпаться напечатать значение указателя на функцию через стандартный консольный поток std::cout, то будет выведено 1. Почему так?


Дело в том, что переменная func имеет тип указателя на функцию, а не просто числовой тип. Вывод зависит от функции-оператора <<, которая имеет кучу прототипов для различных типов:



  • basic_ostream& operator<<( short value );
  • basic_ostream& operator<<( unsigned short value );
  • basic_ostream& operator<<( int value );
  • basic_ostream& operator<<( unsigned int value );
  • basic_ostream& operator<<( long value );
  • basic_ostream& operator<<( unsigned long value );
  • basic_ostream& operator<<( long long value );
  • basic_ostream& operator<<( unsigned long long value ); (since C++11)
  • basic_ostream& operator<<( float value );
  • basic_ostream& operator<<( double value );
  • basic_ostream& operator<<( long double value );
  • basic_ostream& operator<<( bool value );
  • basic_ostream& operator<<( const void* value );
  • basic_ostream& operator<<( const volatile void* value ); (since C++23)
  • basic_ostream& operator<<( std::nullptr_t ); (since C++17)
  • basic_ostream& operator<<( std::basic_streambuf<CharT, Traits>* sb );
  • basic_ostream& operator<<( std::ios_base& (*func)(std::ios_base&) );
  • basic_ostream& operator<<( std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );
  • basic_ostream& operator<<( std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );




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


Зато есть перегрузка для вывода bool. А у указателя любого типа есть преобразование в тип bool, причем оно стоит на первом месте в приоритете по сравнению со всеми другими преобразованиями типов. Соответственно указатель на функцию неявно преобразуется в bool.


Вывести значение адреса можно явно преобразовав указатель на функцию к указателю на void* (перегрузка оператора << для которого как раз печатает значение адреса):



29.7.5.1 Class template basic_ostream [ostream]

namespace std {

template<class charT, class traits = char_traits<charT>>

class basic_ostream : virtual public basic_ios<charT, traits> {

public:

...


// 29.7.5.2, formatted output

basic_ostream<charT, traits>&

operator<<(basic_ostream<charT, traits>& (*pf)(basic_ostream<charT, traits>&));

basic_ostream<charT, traits>&

operator<<(basic_ios<charT, traits>& (*pf)(basic_ios<charT, traits>&));

basic_ostream<charT, traits>&

operator<<(ios_base& (*pf)(ios_base&));


basic_ostream<charT, traits>& operator<<(bool n);

basic_ostream<charT, traits>& operator<<(short n);

basic_ostream<charT, traits>& operator<<(unsigned short n);

basic_ostream<charT, traits>& operator<<(int n);

basic_ostream<charT, traits>& operator<<(unsigned int n);

basic_ostream<charT, traits>& operator<<(long n);

basic_ostream<charT, traits>& operator<<(unsigned long n);

basic_ostream<charT, traits>& operator<<(long long n);

basic_ostream<charT, traits>& operator<<(unsigned long long n);

basic_ostream<charT, traits>& operator<<(float f);

basic_ostream<charT, traits>& operator<<(double f);

basic_ostream<charT, traits>& operator<<(long double f);



То же самое происходит и при выводе в стандартный поток. Указатель преобразуется в bool и прогоняется через bool-вариант функции-оператора <<, и в стандартный поток попадает значение true, которое отображается как 1. В случае же приведения к типу void*, используется вариант с параметром const void* value, который выводит шестнадцатеричное число.


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования