Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > статическое и динамическое связывание


Автор: Gunslinger 11.8.2008, 10:56
читаю "Основные концепции языков программирования", 4ю главу, где Страуструп про переменные пишет. Я так понял, статическое связывание было придумано только для ускорения компилирования и быстрой работы программ, где есть такие переменные. Но имеет ли смысл понимание и использование соответствующих типов связывания сейчас, когда настольные ПК (а тем более серваки) обладают гораздо большими скоростными возможностями? Для мобильных устройст, систем реального времени и прочих малоресурсных систем - смысл есть. Для ПК - преимущества static кажется призрачным, имхо.

Автор: cutwater 11.8.2008, 11:24
Имеется ввиду раннее и позднее либо как называют статическое и динамическое.
Вы ответьте на вопрос, при современных технологиях на велосипед можно навесить реактивный двигатель, так стоит ли отказываться от велосипеда.

Раннее связывание происходит на этапе компиляции и переносить его в рантайм смысла не имеет. Зачем?
Позднее связывание имеет место только для виртуальных методов, когда в процессе исполнения заполняется vtable.

Автор: mes 11.8.2008, 11:35
Цитата(Gunslinger @  11.8.2008,  10:56 Найти цитируемый пост)
Я так понял, статическое связывание было придумано только для ускорения компилирования и быстрой работы программ, где есть такие переменные.


Статическое связывание переменной с типом позволяет провести полную проверку на соблюдение типобезопасности на этапе компиляции.
Т.е после проверки компилятором можно быть увереным, что по  этой части нарушений нет. 
При динамическом связывание вся проверка переносится в рантайм, а ошибка может  долгое  время не проявляться ( пока программа не выполнит ту строчку кода), к тому же определить в чем именно трабла достаточно сложно. 


Автор: Gunslinger 11.8.2008, 11:48
Цитата(mes @ 11.8.2008,  11:35)
Статическое связывание переменной с типом позволяет провести полную проверку на соблюдение типобезопасности на этапе компиляции.
Т.е после проверки компилятором можно быть увереным, что по  этой части нарушений нет. 
При динамическом связывание вся проверка переносится в рантайм, а ошибка может  долгое  время не проявляться ( пока программа не выполнит ту строчку кода), к тому же определить в чем именно трабла достаточно сложно.

Эти преимущества static я знаю. Меня интересует другое его преимущество - скорость работы программы, когда в место динамических переменных используются статические (естественно, где нет списков и прочих меняющихся структур).

Добавлено через 3 минуты и 9 секунд
Цитата(mes @ 11.8.2008,  11:35)
При динамическом связывание вся проверка переносится в рантайм, а ошибка может  долгое  время не проявляться ( пока программа не выполнит ту строчку кода), к тому же определить в чем именно трабла достаточно сложно.

что это? Ничего об этом не знаю. Думал обычный двоичный код, который процессор берет, обрабатывает и кладет обратно. Только один код программы. Что проводит такие проверки?

Автор: mes 11.8.2008, 12:14
Цитата(Gunslinger @  11.8.2008,  11:48 Найти цитируемый пост)
Меня интересует другое его преимущество - скорость работы программы

для обычных программ это преимущество несущественное.



Цитата(Gunslinger @  11.8.2008,  11:48 Найти цитируемый пост)
Думал обычный двоичный код, который процессор берет, обрабатывает и кладет обратно. Только один код программы. Что проводит такие проверки? 

вот этот код и берет переменную, определяет ее тип и в зависимости от типа выбирает нужную реализацию функции для текущей задачи.
Например Вам нужно инкрементировать n-j элемент массива . mas [n] = mas[n]+1;  
а где то выше идет такое : n=1.34523;  mas = 2; 
при строгой статической проверке типов компилятор завопит..
А как должна поступить программа при динамическом связывании типов если у нее нет проверки ?  smile

Цитата(Gunslinger @  11.8.2008,  11:48 Найти цитируемый пост)
когда в место динамических переменных используются статические

в той главе описываются не статические и динамические переменные, а статическое и динамическое связывание типов.. smile 

Автор: cutwater 11.8.2008, 12:36
Автору читать полиморфизм и механизм полиморфизма. 

Автор: Gunslinger 11.8.2008, 16:31
Цитата(mes @  11.8.2008,  12:14 Найти цитируемый пост)
для обычных программ 

Лабораторные? А игры и моделирование-визуализация?

Цитата(mes @  11.8.2008,  12:14 Найти цитируемый пост)
в той главе описываются не статические и динамические переменные, а статическое и динамическое связывание типов.. 

я надеюсь смысл вопроса от этого не потерян? Как я понял, связывание типов - это выделение компилятором памяти либо до выполнения программы (при компиляции), либо во время выполнения. 




Цитата(mes @  11.8.2008,  12:14 Найти цитируемый пост)
вот этот код и берет переменную, определяет ее тип и в зависимости от типа выбирает нужную реализацию функции для текущей задачи.

т.е. компилятор к коду самой программы (инструкции, функции и прочее написанное программистом) добавляет что-то вроде служебной информации - в данном случае проверки типов?

Добавлено через 3 минуты и 34 секунды
Цитата(cutwater @  11.8.2008,  12:36 Найти цитируемый пост)
Автору читать полиморфизм и механизм полиморфизма.

теоретически имею предтавление. на практике реализовывал в виде перегрузки функций. а здесь это что значит?

Автор: cutwater 11.8.2008, 16:54
Ты понял не правильно. Это не выделение памяти в стеке или в куче. На этапе компиляции вся информация о типе без виртуальных ф-ций известна. Если в классе есть хотя бы один виртуальный метод, то создается vptr и vtable, vtable (виртуальная таблица адресов) хранит в себе адреса виртуальных функций и создается во время создания объекта в рантайм.
Это сказывается на быстродействии и на безопасности типов.

Пример
Код

class Base
{
public:
void foo(){cout<<"Base"<<endl;}
}

class Derived : public Bases
{
public:
void foo(){cout<<"Derived"<<endl}
}


Случай 1
Код

Base baseObj;
Derived derivedObj;

baseObj.foo();
derivedObj.foo();

тут и так все понятно
вывод
Код

Base
Derived

Случай 2
Код

Base * pObj = new Derived();

pObj->foo();

а вот тут неожиданность. результат
Код

Base

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

class Base
{
public:
virtual void foo(){cout<<"Base"<<endl;}
}

Собственно я попытался в 2х словах объяснить механизм работы. ЕМНИП Как раз последний пример и относится к позднему связыванию

Автор: mes 11.8.2008, 17:35
Цитата(Gunslinger @  11.8.2008,  16:31 Найти цитируемый пост)
я надеюсь смысл вопроса от этого не потерян? 

вопрос как я понимаю был этот :
Цитата(Gunslinger @  11.8.2008,  10:56 Найти цитируемый пост)
Но имеет ли смысл понимание и использование соответствующих типов связывания сейчас, когда настольные ПК (а тем более серваки) обладают гораздо большими скоростными возможностями? 

1 Понимание программисту всегда необходимо.. Он должен точно представлять что делает. При том что разница далеко не в скорости выполнения smile
2 Использование обуславливается в первую очередь выбором языка. 
Да сегодняшние компьютеры настолько мощны, что для решения большинства  бытовых задач можно безбоязненено в плане скорости использовать язык с динамическим связыванием типов. 

Цитата(Gunslinger @  11.8.2008,  16:31 Найти цитируемый пост)
Лабораторные? А игры и моделирование-визуализация?

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

Автор: Gunslinger 11.8.2008, 18:20
Цитата(mes @  11.8.2008,  17:35 Найти цитируемый пост)
вопрос как я понимаю был этот :

да, так.

и все таки
Цитата(Gunslinger @  11.8.2008,  16:31 Найти цитируемый пост)
т.е. компилятор к коду самой программы (инструкции, функции и прочее написанное программистом) добавляет что-то вроде служебной информации - в данном случае проверки типов?
?

Цитата(cutwater @  11.8.2008,  16:54 Найти цитируемый пост)
то создается vptr и vtable, vtable (виртуальная таблица адресов) хранит в себе адреса виртуальных функций и создается во время создания объекта в рантайм.

К вопросу о том, какую инфу добавляет компилятор к исходнику - спасибо, интересно было узнать.
Но я так и не понял про связывание типов. Те примеры, которые ты привел - это демонстрация полиморфизма.

Уточню еще раз:
статическое связывание типов - переменная объявлена (выделен размер = типу) и инициализирована (присвоено значение). до конца работы программы ее значение не изменится. проводится при компиляции.
динамическое связывание типов - переменная объявлена (выделен размер = типу), но не инициализирована. инициализация (запись значения) происходит во время работы программы.

ps больше ничего не приводит.

Автор: Alek86 11.8.2008, 18:35
Цитата(Gunslinger @  11.8.2008,  18:20 Найти цитируемый пост)
до конца работы программы ее значение не изменится.

это называется "константа"


Цитата(Gunslinger @  11.8.2008,  18:20 Найти цитируемый пост)
динамическое связывание типов - переменная объявлена (выделен размер = типу), но не инициализирована. инициализация (запись значения) происходит во время работы программы.


заметь, после тире у тебя - ни слова о типе

Автор: mes 11.8.2008, 19:15
Цитата(Gunslinger @  11.8.2008,  18:20 Найти цитируемый пост)
Уточню еще раз:
статическое связывание типов - переменная объявлена (выделен размер = типу) и инициализирована (присвоено значение). до конца работы программы ее значение не изменится. проводится при компиляции.
динамическое связывание типов - переменная объявлена (выделен размер = типу), но не инициализирована. инициализация (запись значения) происходит во время работы программы.


статическое связывание типа  - это такой метод работы с ячейкой пямяти , когда тип хранимого там значения известен на момент компиляции и не может быть изменен в процессе выполнения проги. 
динамическое связывание  - это такой метод работы с ячейкой пямяти , когда тип хранимого там значения неизвестен (или не проверяется) на этапе компиляции, а становится известен (и зачастую может быть изменен) только в процесе выполнения. Для обеспечения такой возможности выделяется дополнительная память под хранения типа. 
Виртуальные функции в с++ имеют ограниченное динамическое связывание. 

Цитата(Gunslinger @  11.8.2008,  18:20 Найти цитируемый пост)
т.е. компилятор к коду самой программы (инструкции, функции и прочее написанное программистом) добавляет что-то вроде служебной информации - в данном случае проверки типов?

именно так.. При каждом вызове функции выбирается та которая больше подходит для текушего типа. В случае ненахождения и конфликта возникает ошибка. При статическом возникает в момент компиляции, при динамическом в момент выполнения.. Способы проверки и реакции на ошибку зависят от конретного языка и компилятора. 
Хочу также отметить что виртуальные функции в данном контексте обладают статическим связыванием, и не позволяют сделать перегрузку по их динамическому типу.  Для обхода этого ограничения используют двойную диспетчеризацию, которая предоставляет перегрузку по динамическому типу, сохраняя проверку типов на этапе компиляции..  smile 

Цитата(Gunslinger @  11.8.2008,  18:20 Найти цитируемый пост)
Но я так и не понял про связывание типов. 

не понял относительно своего первого вопроса ?  smile 

Автор: W4FhLF 11.8.2008, 19:38
Отчасти ведь auto и decltype в С++0х будут связаны с вопросом связывания. И хотя в техническом плане связывание так же будет происходить в compile-time, для программиста это будет смотрется немного иначе, ведь явно указывать тип не понадобится, хотя необходимо знать, что где-то он уже указан. 

Автор: Gunslinger 12.8.2008, 08:55
Цитата(Alek86 @  11.8.2008,  18:35 Найти цитируемый пост)
это называется "константа"

попутал да.


Цитата(Alek86 @  11.8.2008,  18:35 Найти цитируемый пост)
заметь, после тире у тебя - ни слова о типе


Цитата(mes @  11.8.2008,  19:15 Найти цитируемый пост)
не понял относительно своего первого вопроса ?

вопрос решен - это был чисто обывательский интерес. Просто сейчас пошел уже не обывательский. К теме топика уже мало отношения имеет, если модератор закроет тему - создам отдельную.


Цитата(mes @  11.8.2008,  19:15 Найти цитируемый пост)
статическое связывание типа  - это такой метод работы с ячейкой пямяти , когда тип хранимого там значения известен на момент компиляции и не может быть изменен в процессе выполнения проги. 

Недопонимаю. Уточняющие вопросы:
    
Код

        int x;
        int y=2;
    

1. тип же всегда известен, в с++ только так переменные и объявляются. Или может быть иначе? 
2. Как тип переменной может быть изменен в процессе выполнения? Имеется ввиду преведение типов?
3. Под статическим связыванием типов я понимаю следующее: int y=2; - тип известен, компилятор выделяет под него память размером int (до выполнения, при компиляции). значение тоже известно - компилятор записывает его в ячейку int y.
4. Создает ли компилятор доп инфу, как в случае с виртуальными функциями для объявленных переменных, но не инициализированных?     int x; или int *p=new int[];

Добавлено через 10 минут и 47 секунд
Цитата(Gunslinger @  12.8.2008,  08:55 Найти цитируемый пост)
Создает ли компилятор доп инфу, как в случае с виртуальными функциями для объявленных переменных, но не инициализированных?     int x; или int *p=new int[];

имею ввиду соответствие название_переменной=адрес

Автор: Partizan 12.8.2008, 09:10
Цитата

компилятор выделяет под него память размером int (до выполнения, при компиляции)


компилятор только компилирует....никакой памяти он "до выполнения, при компиляции" не выделяет...

Цитата

Код

 int x;
 int y=2;

Создает ли компилятор доп инфу, как в случае с виртуальными функциями для объявленных переменных, но не инициализированных?     int x; или int *p=new int[]; 


Вам думаете, что int x; - это позднее связывание?

Автор: Gunslinger 12.8.2008, 09:40
Цитата(Partizan @  12.8.2008,  09:10 Найти цитируемый пост)
компилятор только компилирует....никакой памяти он "до выполнения, при компиляции" не выделяет...

а преобразовать имя переменной к адресу ячейки в памяти?


Цитата(Partizan @  12.8.2008,  09:10 Найти цитируемый пост)
Вам думаете, что int x; - это позднее связывание? 

да. в терминологии с++ - автоматическое.

Автор: Partizan 12.8.2008, 09:52
Цитата(Gunslinger @ 12.8.2008,  09:40)
Цитата(Partizan @  12.8.2008,  09:10 Найти цитируемый пост)
Вам думаете, что int x; - это позднее связывание? 

да. в терминологии с++ - автоматическое.

эээ...автоматическое? к сожалению не знаю такого термина....
что по-вашему при объявлении переменной int x с чем связывается?

Добавлено через 5 минут и 52 секунды
а вообще по хорошему автору надо курить полиморфизм...тогда не будет таких вопросов...

Автор: mes 12.8.2008, 10:37
Цитата(Gunslinger @  12.8.2008,  08:55 Найти цитируемый пост)
1. тип же всегда известен, в с++ только так переменные и объявляются. Или может быть иначе? 
2. Как тип переменной может быть изменен в процессе выполнения? Имеется ввиду преведение типов?
3. Под статическим связыванием типов я понимаю следующее: int y=2; - тип известен, компилятор выделяет под него память размером int (до выполнения, при компиляции). значение тоже известно - компилятор записывает его в ячейку int y.
4. Создает ли компилятор доп инфу, как в случае с виртуальными функциями для объявленных переменных, но не инициализированных?     int x; или int *p=new int[];

1. 
Цитата(Gunslinger @  11.8.2008,  10:56 Найти цитируемый пост)
 "Основные концепции языков программирования", 4ю главу, где Страуструп 

А вы не обратиле внимание , что в этой книжке не только о с++ пишется.
 также непонятно где Вы там Страуструпа нашли 
Примером динамического связывания  в с++ является (реализованый разными стороними библиотеками)  тип Variant. 
2. Не в c++ делается примерно так: a=3; (сейчас у а тип инт) а = "строка"; (теперь тип строка)  
разновидностей и подходов много и зависит от реализации конкретного языка
3. пямять выделяется не под тип, а под переменную.
4. Как связан тип с инициализацией ? вот ограниченный пример динамического связывания
Код

TBase *p;  // указатель типа TBase
p = new TDerived(); // указывает на TDerived (наследник TBase) 
p->virt_func(); // вызов реализации функции класса TDerived 
func (p); // не смотря на то что указатель связан с классом TDerived, произойдет вызов перегруженной функции для класса TBase.
// в языках с динамическим связыванием вызвалась бы перегруженая для TDerived функция


Автор: Gunslinger 12.8.2008, 11:30
Цитата(Partizan @  12.8.2008,  09:52 Найти цитируемый пост)
эээ...автоматическое? к сожалению не знаю такого термина....

в той книге написано, что кроме динамического связывания есть еще и автоматическое, а в с++ int x=2 - автоматическое. просто щас каша в голове, хотел как-то разграничить. 


Цитата(Partizan @  12.8.2008,  09:52 Найти цитируемый пост)
а вообще по хорошему автору надо курить полиморфизм...тогда не будет таких вопросов... 

я бы покурил, только инфы на википедии мне не достаточно, а из книг я изучал с++ только по Уолтеру Савичу, там полиморфизм функций описан. Я так думаю, термин "связывание типов" - это описание какого-то процесса на уровне железа и двоичного кода. Только никак не могу понять какого.

Цитата(Partizan @  12.8.2008,  09:52 Найти цитируемый пост)
что по-вашему при объявлении переменной int x с чем связывается?

с физическим адресом ячейки памяти.


Цитата(mes @  12.8.2008,  10:37 Найти цитируемый пост)
А вы не обратиле внимание , что в этой книжке не только о с++ пишется.
 также непонятно где Вы там Страуструпа нашли

обратил, но интересуюсь только с++. Про Страуструпа было в начале, вот и решил, что эту главу написал он.


Цитата(mes @  12.8.2008,  10:37 Найти цитируемый пост)
Не в c++ делается примерно так: a=3; (сейчас у а тип инт) а = "строка"; (теперь тип строка)

я что-то пропустил? когда стали писать как в питоне?

Автор: cutwater 12.8.2008, 11:33
Цитата(Partizan @  12.8.2008,  09:52 Найти цитируемый пост)
а вообще по хорошему автору надо курить полиморфизм...тогда не будет таких вопросов... 


Я об этом уже говорил. Просто автор не понимает о чем пишет, почитайте Шилдта или Страуструпа. Там очень хорошо описаны полиморфизм и связывание.
Автору так же смотреть мой пример выше.

Автор: mes 12.8.2008, 18:49
Цитата(Gunslinger @  12.8.2008,  11:30 Найти цитируемый пост)
Не в c++ делается примерно так: a=3; (сейчас у а тип инт) а = "строка"; (теперь тип строка)

я что-то пропустил? когда стали писать как в питоне? 

пропустили частицу "не" в начале цитаты.. ;)



Цитата(Gunslinger @  12.8.2008,  11:30 Найти цитируемый пост)
что по-вашему при объявлении переменной int x с чем связывается?
с физическим адресом ячейки памяти.

Код

union { int i; float  f; };

в данном примере i и f занимают одну и туже физическую ячейку памяти (делает это структура union) , однако тип у обоих переменных разных .  Тип  - это проявление взаимодействия со значением. Некая сущность, которая определяет какие виды взаимодействия и каким образом подерживаются.  



Автор: Gunslinger 13.8.2008, 20:22
Цитата(mes @  12.8.2008,  18:49 Найти цитируемый пост)
Тип  - это проявление взаимодействия со значением. Некая сущность, которая определяет какие виды взаимодействия и каким образом подерживаются.

т.е. должны быть проверки для того, чтобы это определить?

Добавлено через 4 минуты и 14 секунд
в смысле проверки - работа компилятора.

Автор: mes 14.8.2008, 14:10
Цитата(Gunslinger @  13.8.2008,  20:22 Найти цитируемый пост)
т.е. должны быть проверки для того, чтобы это определить?

точнее сказать не проверка, а выбор функции.
Т.е вид взаимодействия с ячейкой (оно и есть выбор подходяшей реализации функции) осушествляется на основе типа значения.

Например у нас есть функция print(). Для работы с разными типами мы перегружаем ее :
Код

void print (int i) {..}
void print (char c) {..}
void print (char * pc) {..}
void print ...
// в компиляторе оно формитуется в условный код :
void print <int>      (addr) {..}
void print <char>  (addr) {..}
void print <pchar>(addr) {..}
void print ...
// где в <> указан тип функции , а addr - адрес ячейки , естественно все тело функции заменяется подобным способом.
// и получается что после компиляторное представление программы работает уже без знания типа значения
// т.е имеем например такие вызовы функции

int i=7;
print(i); 
print(5); 
print ("a");
print (´a´);
print ((int)'a');

// что преобразуется в подобный код:
print<int>(addr12); 
print<int>(5); 
print <pchar>(addr20);
print <char>(97);
print<int>(97); 

// где addr12 и addr20 адреса переменной i и строки "a"';



Добавлено через 1 минуту и 30 секунд
в языках с динамическим типом переменых, выбор подходяшей функции (вышеразобранная ситуация)  происходит не во время компиляции,а во время выполнения. 

Автор: Gunslinger 15.8.2008, 15:25
Цитата(mes @  14.8.2008,  14:10 Найти цитируемый пост)
Например у нас есть функция print(). Для работы с разными типами мы перегружаем ее

меня интересовало связывание на уровне компилятора, а полиморфизм я считал только логической штукой для удобства программирования. так вот при чем здесь полиморфизм.

Автор: Partizan 15.8.2008, 16:58
Цитата(Gunslinger @ 15.8.2008,  15:25)
Цитата(mes @  14.8.2008,  14:10 Найти цитируемый пост)
Например у нас есть функция print(). Для работы с разными типами мы перегружаем ее

меня интересовало связывание на уровне компилятора, а полиморфизм я считал только логической штукой для удобства программирования. так вот при чем здесь полиморфизм.

Gunslinger, полиморфизм как он есть возможен как раз благодаря позднему связыванию.

Автор: mes 16.8.2008, 00:04
Цитата(Partizan @  15.8.2008,  16:58 Найти цитируемый пост)
полиморфизм как он есть возможен как раз благодаря позднему связыванию. 

обычно под словом "позднее связывaние" подразумевает связывание в режиме выполнения...
 полиморфизм бывает статический и динамический. Динамический выполняется в рантайм, а статический на этапе компиляции(т.е на при раннем связывании)

Добавлено через 1 минуту и 52 секунды
Цитата(Gunslinger @  15.8.2008,  15:25 Найти цитируемый пост)
меня интересовало связывание на уровне компилятора, а полиморфизм я считал только логической штукой для удобства программирования. так вот при чем здесь полиморфизм. 

полиморфизм эта одна одно из проявлений связывания типов. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)