Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Почему такой код компилируется (про приведение типов)? / 20 сообщений из 20, страница 1 из 1
23.04.2017, 17:39
    #39442911
baden_baden
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Можно понять, почему компилятор не может разобраться с указателями.
Но почему он работает и что именно выводит (судя по всему, неопределённое поведение, но непонятно, на какие участки памяти смотрит).

Код: plaintext
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.
#include <string.h>
#include <iostream>

class A {
	int i;
	std::string str;
public:
	A(int _i) : i(_i), str("class_a_str") { }
	void DoA() { std::cout << "A::DoA  " << i << std::endl; }
};

class B {
	std::string s;
public:
	B(std::string _s) : s(_s) { }
	void DoB() { std::cout << "B::DoB  " << s << std::endl; }
};

int main() {

	A a(1);
	B b("str");

	((A*)((void*)&b))->DoA();
	((B*)((void*)&a))->DoB();
	
	return 0;
}



Вывод такой обычно, причём число обычно меняется.
Код: plaintext
1.
2.
A::DoA  7023844
B::DoB
...
Рейтинг: 0 / 0
23.04.2017, 17:56
    #39442913
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
baden_baden
Код: plaintext
1.
2.
((A*)((void*)&b))->DoA();
((B*)((void*)&a))->DoB();



компилятор виноват лишь в том, что позволяет выстрелить себе в ногу.
ну зачем ты этот бред написал?
что сказать этим хотел?
...
Рейтинг: 0 / 0
23.04.2017, 17:59
    #39442916
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Что тут непонятного?
Это
Код: plaintext
1.
	((A*)((void*)&b))->DoA();


означает указание компилятору: "ты не умничай, а делай как я сказал, я за все отвечаю". Ну так и отвечай.
...
Рейтинг: 0 / 0
23.04.2017, 18:01
    #39442917
baden_baden
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Изопропил,

из-за любознательности. А размеры полей же разные, верно? Значит, при печати (и других операциях) берутся соответствующие участки памяти, на которых может хранится всё, что угодно, потом эти участки обрабатываются, как соответствующие типы (в том числе неподходящие) -- из-за этого и получается неопределённое поведение?
...
Рейтинг: 0 / 0
23.04.2017, 18:04
    #39442918
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Нет тут неопределенного поведения. Все четко и однозначно, если понимаешь зачем такое пишешь.
...
Рейтинг: 0 / 0
23.04.2017, 18:08
    #39442920
baden_baden
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
А почему тогда цифры разные появляются при исполнении?
A::DoA 7023844
...
Рейтинг: 0 / 0
23.04.2017, 18:25
    #39442926
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
baden_badenА почему тогда цифры разные появляются при исполнении?
A::DoA 7023844
Смотри реализацию std::string, внутрь которой ты лезешь.
...
Рейтинг: 0 / 0
23.04.2017, 18:29
    #39442927
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
baden_badenА почему тогда цифры разные появляются при исполнении?
A::DoA 7023844
посмотри исходник std::string и ассемблерное порождение
...
Рейтинг: 0 / 0
23.04.2017, 18:56
    #39442937
baden_baden
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
В string память выделяется под массив char, а программа с участком выделяемой памяти работает, думая, что это int?
...
Рейтинг: 0 / 0
23.04.2017, 19:07
    #39442944
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
разрывная, раскинул мозгами Штирлиц
...
Рейтинг: 0 / 0
23.04.2017, 19:13
    #39442947
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
baden_badenВ string память выделяется под массив char, а программа с участком выделяемой памяти работает, думая, что это int?
Программа работает не думая. Думать это задача разработчика, как написал так и работает. Учи мат.часть, книжку какую-нибудь почитай, вместо того чтобы опыты ставить. Тут не физика, опыты не нужны, работает точно так как в документации написано.
...
Рейтинг: 0 / 0
23.04.2017, 19:36
    #39442955
baden_baden
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Dima T,

Не могли бы подсказать книжку, а лучше даже главу?
...
Рейтинг: 0 / 0
24.04.2017, 05:29
    #39443007
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
baden_badenНе могли бы подсказать книжку, а лучше даже главу?Подозреваю, книжку такую ты вряд ли найдёшь. Советую посмотреть генерируемый ассемблерный код под дебагом, тогда всё станет понятно.
Ну и основное уже сказали: компилятор сделал то, что ты просил, поэтому претензии к компилятору тут неуместны уже :)
...
Рейтинг: 0 / 0
24.04.2017, 07:30
    #39443017
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
baden_badenНе могли бы подсказать книжку, а лучше даже главу?

Если такая книжка и есть, то она должна называться "С/С++ Вредные советы". Читай книги где пишут как делать правильно и старайся обойтись тем что написано, а не искать лайфхаки.

Гугли про приведение типов . Там описано как это правильно делать. В твоем примере правильно сделать невозможно, т.к. в твоем коде изначально присутствует ошибка проектирования и исправлять надо ее.
...
Рейтинг: 0 / 0
24.04.2017, 07:43
    #39443020
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Dima TЕсли такая книжка и есть, то она должна называться "С/С++ Вредные советы".
зачем же так сурово.

подойдут главы книг по компиляторам, посвящённые кодогенерации, в частности - по управлению памятью
...
Рейтинг: 0 / 0
24.04.2017, 11:09
    #39443121
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
Давай детально разберём код.


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
#include <string.h>
#include <iostream>

class A {
	int i;
	std::string str;
public:
	A(int _i) : i(_i), str("class_a_str") { }
	void DoA() { std::cout << "A::DoA  " << i << std::endl; }
};



Класс A неполиморфный, содержит две переменных : int и string.
int положим 4 байта, string содержит указатель на буфер или на реализацию буфера, положим ещё 4 байта.


Код: plaintext
1.
2.
3.
4.
5.
6.
class B {
	std::string s;
public:
	B(std::string _s) : s(_s) { }
	void DoB() { std::cout << "B::DoB  " << s << std::endl; }
};



Класс B, также неполиморфный, содержит одну переменную : string.
которая содержит указатель на буфер или на реализацию буфера длиной 4 байта.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
int main() {

	A a(1);
	B b("str");

	((A*)((void*)&b))->DoA();
	((B*)((void*)&a))->DoB();
	
	return 0;
}



Мы объявляем переменную класса A, затем переменную класса B.

Затем берём адрес переменной класса B и даём инструкцию интерпретировать его как адрес переменной класса A (тут кстати неопределённое поведение и будет
при приведении void* к A* ) и хотим вызвать метод класса A через этот указатель.

В классе B первая и единственная ячейка памяти размером в 4 байта содержит одну переменную : string.
которая содержит указатель на буфер или на реализацию буфера.

Функция DoA() будет интерпретировать эту ячейку как переменную A::i типа int и выведет её значение в cout.
Что она при этом напечатает -- неизвестно, ибо там лежит неведомая хрень (указатель на буфер или на реализацию буфера длиной 4 байта)

То же самое будет и во втором случае, но немного хуже -- при вызове

<< s

может произойти защита памяти и крах приложения.

И ещё раз -- тут два места с неопределённым поведением -- два привидения void* к A* и B*.
...
Рейтинг: 0 / 0
24.04.2017, 11:33
    #39443137
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
MasterZiv
да там можно просто показать кусочек ассемблерного кода, который лезет не туда в стеке
...
Рейтинг: 0 / 0
24.04.2017, 11:48
    #39443146
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
CEMbда там можно просто показать кусочек ассемблерного кода, который лезет не туда в стеке
Куда указано - туда и лезет.
Мусор на выходе заказывали - получите и распишитесь.
...
Рейтинг: 0 / 0
24.04.2017, 11:59
    #39443155
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
ИзопропилКуда указано - туда и лезет.
Мусор на выходе заказывали - получите и распишитесь.да, но я к тому, что лучше посмотреть на реализацию, и понять , как так получилось. Многие люди слишком абстрактно воспринимают концепции языка. А явные примеры компиляции кода хорошо ставят мозг на место.
...
Рейтинг: 0 / 0
24.04.2017, 14:40
    #39443321
code_cpp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Почему такой код компилируется (про приведение типов)?
MasterZiv,

Вам и остальным -- спасибо за ответы.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Почему такой код компилируется (про приведение типов)? / 20 сообщений из 20, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]