Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.53/79: Рейтинг темы: голосов - 79, средняя оценка - 4.53
-2 / 8 / 2
Регистрация: 10.11.2008
Сообщений: 776

Размер указателя

25.04.2016, 18:36. Показов 16915. Ответов 75
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
sizeof(void*);// Размер указателя на любой тип равен 8, почему так много? И можно ли как-нибудь узнать сколько под указатель выделено памяти не смотря в исходники?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.04.2016, 18:36
Ответы с готовыми решениями:

Размер строки указателя
char *str = new char ; str = "123"; sizeof(str) - отображает размер указателя, а как вывести размер самой строки строки?

Размер указателя short int
Доброе утро. Возник вопрос почему short int = 8 байт? Он же должен занимать 2 байта в 32-х разрядной среде. #include...

Размер указателя на разные типы данных
еще один вопрос к етой теме почуму придавая указателю * prt тип short int или double функция sizeof так же выводит 4 как при int?

75
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
29.04.2016, 16:27
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от avgoor Посмотреть сообщение
Но, зачем городить огород (особенно новый keyword) если это не дает никакого профита?
Профит как раз есть. Во-первых, копирование/сравнение голых void* проще и быстрее того же самого для std::pair<void*,int>. Тупо потому что void* можно обработать одной командой процессора, а std::pair<void*,int> - нельзя. Во-вторых, команда вычитания из this константы, работает быстрее команды вычитания из this значения в памяти.

При этом нужно все это лишь там, где программист откатывается на уровень Си и начинает тамогочить на низком уровне все и вся, осторожно огибая сопутствующие грабли. Конкретно в этой ситуации никакой проблемы с новым кейвордом не вижу. А сишники, кстати, не видят проблемы и с конструкциями вида struct MyStruct*value (без struct не компилируется) или (void)value; (вместо использования безымянных аргументов функции). Хотя, это уже их личные сексуальные извращения, в плюсах удаленные.
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
29.04.2016, 17:12
Цитата Сообщение от Renji Посмотреть сообщение
работает быстрее команды вычитания из this значения в памяти.
Не забывайте о лишнем прыжке - то на то и выйдет
Цитата Сообщение от Renji Посмотреть сообщение
Во-первых, копирование/сравнение голых void* проще и быстрее
sse в помощь.
Цитата Сообщение от Renji Посмотреть сообщение
Конкретно в этой ситуации никакой проблемы с новым кейвордом не вижу
Проблема в том, что этот новый кейворд увеличивает связанность отдельных единиц трансляции (которая де-факто не нужна).

Добавлено через 26 минут
Т.к. тема пошла по кругу сформулирую вопрос.

Например, я использую указатель на класс и указатель на функцию член как делегат. Зачем требовать какую-то дополнительную информацию о делегате (ваше ключевое слово), если по логике класс о делегате должен знать как можно меньше?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
29.04.2016, 17:27
Цитата Сообщение от avgoor Посмотреть сообщение
Не забывайте о лишнем прыжке - то на то и выйдет
Как раз таки забывайте. Во-первых, вот здесь третий рисунок гляньте - при переносе в trace-кэш переход просто выкидывается. Во-вторых, прыжок влияет только на механизм закидывания микроопераций в конвейер. А он один фиг работает с опережением (иначе нет смысла делать конвейер).
Цитата Сообщение от avgoor Посмотреть сообщение
Проблема в том, что этот новый кейворд увеличивает связанность отдельных единиц трансляции (которая де-факто не нужна).
Можно и без кейворда, всегда полагаясь на присутствие вызывалки.
Цитата Сообщение от avgoor Посмотреть сообщение
Например, я использую указатель на класс и указатель на функцию член как делегат.
Указатель на класс приводим к void*, указатель на функцию-член приводим к void*. При обращении к делегату указатель на класс копируем в rcx и делаем call на начало функции-члена. Избегая преобразований this как класса. Или я что-то недопонял в необходимой функциональности делегата?
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
09.05.2016, 10:05
Цитата Сообщение от warhast Посмотреть сообщение
А ведь можно и так:
C++
1
2
3
4
5
6
#include <iostream>
struct S {};
int main() {
* int (S::*p)();
* std::cout << sizeof(p);
}
На х64 это 16 байт.
Зависит от компилятора. У меня VC2008/2015 выдают здесь sizeof (pointer),
т.е. 4 байта в x86 и 8 байт в x64.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13234 / 6866 / 1827
Регистрация: 18.10.2014
Сообщений: 17,400
09.05.2016, 10:09
Цитата Сообщение от Убежденный Посмотреть сообщение
Зависит от компилятора. У меня VC2008/2015 выдают здесь sizeof (pointer),
т.е. 4 байта в x86 и 8 байт в x64.
Потому что по умолчанию для таких указателей в VC работает режим "никакого множественного наследования". Работать такие указатели будут в общем случае неправильно.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
09.05.2016, 11:37
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Работать такие указатели будут в общем случае неправильно.
Можно пример неправильности?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13234 / 6866 / 1827
Регистрация: 18.10.2014
Сообщений: 17,400
09.05.2016, 18:14
Цитата Сообщение от Убежденный Посмотреть сообщение
Можно пример неправильности?
Тут, по-моему, вся тема посвящена этим примерам.

У меня уже нет под руками более старых версий VS, только 2015. VS2015 уже перестал агресcивно уменьшать указатели, и на каждую попытку создать ошибочный пример либо строит большой указатель, либо выдает сообщение об ошибке

Например

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
#include <iostream>
 
struct S 
{ 
  int a = 42; 
 
  int foo()
  {
    return a;
  }
};
 
struct D : S
{
  virtual ~D() {}
 
  int bar()
  {
    return a;
  }
};
 
int main()
{
  int (S::*ps)() = &S::foo;
  S s;
 
  std::cout << sizeof ps << " " << (s.*ps)() << std::endl;
 
  int (S::*pd)() = static_cast<int (S::*)()>(&D::bar);
  D d;
 
  std::cout << sizeof pd << " " << (d.*pd)() << std::endl;
}
При компиляции в 64-битном режиме размер указателя - 16, а не 8 (хотя и наследование, как видите, даже не множественное). Можно загнать его в 8, если явно указать

C++
1
#pragma pointers_to_members( best_case, single_inheritance )
но тогда будет ошибка на static_cast.

А в VS2008 такой пример скорее всего скомпилируется (нет возможности попробовать) со всеми вытекающими.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
09.05.2016, 18:42
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
А в VS2008 такой пример скорее всего скомпилируется
int a=42;//это круто для 2008
но с конструктором инициализирующим a всё скомпилировалось и работает:
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
#include <iostream>
 
struct S 
{ 
  int a;
  S():a(42){} 
 
  int foo()
  {
    return a;
  }
};
 
struct D : S
{
  virtual ~D() {}
 
  int bar()
  {
    return a;
  }
};
 
int main()
{
  int (S::*ps)() = &S::foo;
  S s;
 
  std::cout << sizeof ps << " " << (s.*ps)() << std::endl;//4 42
 
  int (S::*pd)() = static_cast<int (S::*)()>(&D::bar);
  D d;
 
  std::cout << sizeof pd << " " << (d.*pd)() << std::endl;//4 мусор
  system("pause");
    return 0;
}
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13234 / 6866 / 1827
Регистрация: 18.10.2014
Сообщений: 17,400
09.05.2016, 19:18
Цитата Сообщение от IGPIGP Посмотреть сообщение
но с конструктором инициализирующим a всё скомпилировалось и работает:
Что значит "работает" если вы же сами в комментарии написали (еле разглядел), что во втором случае в выводе получился мусор?
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
09.05.2016, 20:58
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Что значит "работает"
Логическая ошибка есть. И это я написал. Программа завершилась с кодом 0. Это я имел ввиду.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13234 / 6866 / 1827
Регистрация: 18.10.2014
Сообщений: 17,400
09.05.2016, 21:21
Цитата Сообщение от IGPIGP Посмотреть сообщение
Логическая ошибка есть. И это я написал. Программа завершилась с кодом 0. Это я имел ввиду.
Завершение с кодом 0 - это, понятное дело, лишь редкое случайное везение. По напечатанному мусору понятно, что вызов D::bar() получил неправильный указатель this. А это уже может привести к чему угодно.

И непонятно, о какой логической ошибке идет речь. С точки зрения языка ошибка здесь - в компиляторе. Это "логическая"?
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
09.05.2016, 22:11
Я не уверен как это всё высказать, но если это можно высказать, то я бы так попробовал:
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
#include <iostream>
struct S 
{ 
  int a;
  S():a(42){} 
 
  int foo()
  {
    return a;
  }
};
struct SS 
{ 
  int a;
  SS():a(52){} 
   int foo()
  {
    return a;
  }
};
 
struct D : S
{
D():S(){}
virtual ~D() {}
   int bar()
  {
    return a;
  }
};
 
int main()
{
  int (S::*ps)() = &S::foo;
  S s;
 
  std::cout << sizeof ps << " " << (s.*ps)() << std::endl;//4 42
// int (S::*pd)() = static_cast<int (S::*)()>(&D::bar);//это приведение методов
//объявленных в одном классе (struct D) один за другим
//давайте заменим его более корректным:
  int (D::*pd)() = static_cast<int (S::*)()>(&D::foo);
  
  D d;
  //тогда вызов 
  std::cout << sizeof pd << " " << (d.*pd)() << std::endl;//4 42 вполне вменяем
  //это потому что D::foo и S::foo это указатели на методы объявленные одинаково
  //точнее это один и тот же метод :j
//то есть за приведение и разыменование ответственность на программисте
//разве это новость?
 
//а тут компилятор на страже нравственности и целомудрия:
//int (SS::*pd)() = static_cast<int (SS::*)()>(&S::foo);//это приведение методов
//он говорит:
//(24464):error C2440: static_cast: невозможно преобразовать 'int (__thiscall S::* )(void)' в 'int (__thiscall SS::* )(void)'1> 
//Типы, на которые указывают указатели, не связаны; для преобразования требуется reinterpret_cast, приведение в стиле С или приведение в стиле функции
//а давайте попробуем:
int (S::*pdd)() = reinterpret_cast<int (S::*)()>(&SS::foo);
std::cout<<(s.*pdd)()<<std::endl;//42 
//бандитизмЪ но продолжим:
int (SS::*pss)() = reinterpret_cast<int (SS::*)()>(&S::foo);
SS ss;
std::cout<<(ss.*pss)()<<std::endl;//52 :)
  system("pause");
    return 0;
}
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13234 / 6866 / 1827
Регистрация: 18.10.2014
Сообщений: 17,400
09.05.2016, 22:46
Цитата Сообщение от IGPIGP Посмотреть сообщение
C++
1
2
//давайте заменим его более корректным:
//тогда вызов ... вполне вменяем
Не совсем понимаю, что тут является "более корректным" и зачем вообще что-то заменять. Оба варианта - совершенно корректны и ничего необычного (или "невменяемого") в моем исходном варианте нет.

На самом деле ваш вариант с

C++
1
int (D::*pd)() = static_cast<int (S::*)()>(&D::foo);
убрал из примера все то "интересное", ради которого мой пример создавался. В вашем варианте нет расхождения между типом указателя int (S::*)() и типом метода. Выражение &D::foo тоже имеет тип int (S::*)() и, поэтому, static_cast тут уже совершенно не нужен. Такой вариант может/будет работать даже с неправильным "урезанным" указателем на метод, т.е. этот вариант - совершено непоказателен. К чему он тут?

(И к чему тут пример с reinterpret_cast - мне тоже не ясно.)

Цитата Сообщение от IGPIGP Посмотреть сообщение
C++
1
2
//то есть за приведение и разыменование ответственность на программисте
//разве это новость?
О чем тут идет речь? Еще раз: мой пример совершенно легален и корректен. Никаких "ответственностей программиста" в нем не нарушено. Никаких "хаков" в моем примере нет. То, что ваш компилятор выдал "мусор" - это баг (точнее, багофича) вашего компилятора, а не моего кода. Это та самая багофича, о которой я говорил здесь: Размер указателя
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
10.05.2016, 00:16
Цитата Сообщение от IGPIGP Посмотреть сообщение
C++
1
int (S::*pd)() = static_cast<int (S::*)()>(&D::bar);
TheCalligrapher, я вижу создание указателя на метод класса S. Взят указатель на метод класса D (которого нет в классе S и который объявлен и определён после метода foo в классе D), который кастится к методу из S и получается указатель на метод в S. Но там нет и не может быть такого адреса. Что же тут легального?
А попытка вызвать метод по указателю от одного класса на экземпляре другого, это ещё один "легальный" момент? У меня маловато опыта, чтобы высказаться определённо.
Мне это представляется нелегальным кодом. Если компилятор неправ в том, что он это компилирует, то можно добавить ещё 100500 вариантов которые компиляторы C++ компилируют и которые являются UB. Это плата за близость к телу твердого и мягкого вейера. Или я не понял о чем речь.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13234 / 6866 / 1827
Регистрация: 18.10.2014
Сообщений: 17,400
10.05.2016, 01:42
Цитата Сообщение от IGPIGP Посмотреть сообщение
TheCalligrapher, я вижу создание указателя на метод класса S. Взят указатель на метод класса D (которого нет в классе S и который объявлен и определён после метода foo в классе D), который кастится к методу из S и получается указатель на метод в S. Но там нет и не может быть такого адреса. Что же тут легального?
Это вы тут сами чего-то напридумывали.

Легального тут то, что стандарт языка С++ не требует и никогда и не требовал того, чтобы в момент инициализации указателя типа int (S::*)() этот указатель указывал на что-то, присутствующее именно в классе S. Вы можете заставить указатель int (S::*)() указывать на член класса-потомка. Ясно, что такая инициализация таит в себе определенную опасность, по каковой причине она требует выполнения явного static_cast (заметьте - static_cast, а не reinterpret_cast). Тем не менее такое преобразование является частью функциональности static_cast и ничего нелегального в ней нет.

Требование наличия члена в классе в языке С++ перенесено на более поздний момент: момент разадресования указателя, т.е. выполнения операторов .* и ->*. Именно в этот момент требуется, чтобы динамический тип объекта, указанный слева от .* и ->*, содержал указуемый член класса. Проверка такого требования, понятное дело, не может быть выполнена на этапе компиляции, поэтому следить за его соблюдением - это обязанность программиста. Нарушение его - UB. В моем примере это требование соблюдается, поэтому ничего нелегального в моем примере нет.

Именно это открытым текстом сказано в Note в спецификации static_cast (5.2.9/12)

[ Note: although class B need not contain the original member, the dynamic type of the object with which indirection through the pointer to member is performed must contain the original member; see 5.5. —end note ]
Именно эта возможность и ведет к тем тонкостям с реализацией указателей на члены, о которых мы столько времени разговаривали в этой теме.

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

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
#include <iostream>
 
class AbstractAlgorithm
{
protected:
 
  typedef void (AbstractAlgorithm::*VirtualMethod)();
 
  AbstractAlgorithm(VirtualMethod init, VirtualMethod work, VirtualMethod done) :
      init(init), work(work), done(done)
    {}
 
public:
 
  void run()
  {
    std::cout << "Initialization..." << std::endl;
    (this->*init)();
    std::cout << "Running..." << std::endl;
    (this->*work)();
    std::cout << "Finishing up..." << std::endl;
    (this->*done)();
    std::cout << "Done." << std::endl;
  }
 
private:
  VirtualMethod init, work, done;
};
 
class SpecificAlgorithm : public AbstractAlgorithm
{
public:
 
  SpecificAlgorithm() : AbstractAlgorithm(
      static_cast<VirtualMethod>(&SpecificAlgorithm::init),
      static_cast<VirtualMethod>(&SpecificAlgorithm::work),
      static_cast<VirtualMethod>(&SpecificAlgorithm::done)),
      a(0)
    {}
 
private:
 
  int a;
 
  void init() 
    { a = 42; }
 
  void work() 
  { 
    a *= 2; 
    std::cout << "  Result = " << a << std::endl;  
  }
 
  void done() 
    { a = 0; }
};
   
int main()
{
  SpecificAlgorithm().run();
}
P.S. Один из поздних черновиков первого стандарта С++ следовал именно вашей логике и запрещал такое приведение типов. Указатель на член класса S мог указывать только на то, что явно есть в S. Однако в последний момент эта функциональность была изменена и включена в чистовой вариант стандарта C++98: появилась возможность делать "опасный" static_cast, а требование наличия указуемого члена в классе переехало в спецификацию операторов .* и ->*.
5
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
10.05.2016, 08:22
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
У меня уже нет под руками более старых версий VS, только 2015. VS2015 уже перестал агресcивно уменьшать указатели, и на каждую попытку создать ошибочный пример либо строит большой указатель, либо выдает сообщение об ошибке
Например
...
Да, любопытный примерчик.
У меня VC2008 и VS2015 ведут себя одинаково (для VC2008 я только перенес
инициализацию 'a' в конструктор):
> 8 42
> 8 -858993460 (мусор)
При этом код в обоих случаях компилируется с предупреждением C4407
"cast between different pointer to member representations, compiler may generate incorrect code"
на строчке, где static_cast.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.05.2016, 08:22

Как верно узнать размер указателя ?
СBaseTest* pTest = { new СBaseTest, new СOther }; Нужно узнать размер pTest

Объяснить от чего зависит размер указателя и что такое арифметика указателей
Уважаемые программисты, возник вопрос. По умолчанию указатель любого типа может иметь только 4 байта. Но взглянем на следующий код: ...

Почему увеличение указателя на sizeof(тип) не тождественно инкременту этого же указателя?
Всем доброго дня.:) Можете обьяснить ,почему при инкриментировании указателя,его значение(адресс) увеличивается на 4 (размер int в...

Создание указателя на экземпляр класса, описанного после объявления указателя
Здравствуйте! Проблема в том, что нужно сделать так: class A{ public: B* b = nullptr; }; class B{ public:

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


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

Или воспользуйтесь поиском по форуму:
76
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru