Для компилятора все переменные int* это синонимы. То есть компилятор считает что где-то в программе есть один единственный int и все переменные типа int* ссылаются на него, то есть являются синонимами одного единственного инта. Об этом дальше и идет речь.Указатель - это данное, хранящее адрес. Он не может быть синонимом чего либо за одним исключением - можно объявить одну или несколько ссылок и на указатель, тогда несколько указателей будут синонимичны друг другу.
А что, на функцию может быть не только указатель, но и ссылка?
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
2B OR NOT(2B) = FF
При том, что они заведомо не равны? Однако! Кстати, если она вдруг окажутся равны, а ты используешь их оба, то сума будет правильной, а вот если наоборот, то ты удвоишь одно слагаемое.int *a = foo();
int *b = bar();
*a += 10;
return *a + *b;
}
Если ты попытаешься написать коспилятор Си (*), то ты поймешь что в общем случае невозможно определить a или b во время выполнения будут равны или не равны. Поэтому компилятор С всегда исходит из пессимистического предположения что они равны.
Код: Выделить всё
int x=2;
int y=3;
return x+y;
Код: Выделить всё
return x+x;
Код: Выделить всё
return y+y;
Код: Выделить всё
int x=2;
int y=2;
return x+y;
Код: Выделить всё
int x=2;
int &y=x;
return x+y;
Код: Выделить всё
int &y=x;
Код: Выделить всё
int x=2;
int &y=x;
return x+x;
Код: Выделить всё
int x=2;
int *y=&x;
return x+*y;
Код: Выделить всё
int x=2;
int &y=x;
return x+x;
Код: Выделить всё
int x=2;
int *y=&x;
return x+*y;
Код: Выделить всё
int x=2;
int *y=&x;
int d;
std::cin>d;
y+=d;
y-=4;
return x+*y;
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Почему заведомо? Даже если foo() и bar() это не extern функции, чтобы понять что они возвращают в общем случае надо решить т.н. "проблему останова". Алан Тьюринг в 1936 году доказал что она неразрешима.При том, что они заведомо не равны?
2B OR NOT(2B) = FF
А ты свой текст читал? Ну хорошо:Почему заведомо?
Код: Выделить всё
int x=2;
int y=2;
int *z=&x;
int *t=&y;
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
z и t это переменные, они могут измениться. Никто не будет ходить по control flow graph'у чтобы при помощи автоматического доказательства теорем доказать что они всегда не равны. Компилятор должен работать быстро, а иначе люди будут сердиться и плеваться.Код: Выделить всё
int x=2; int y=2; int *z=&x; int *t=&y;
В С99 можно сказать явно что они никогда не равны, а если равны то это ошибка и undefined behavior.
Тут явно указывано что z и t никогда не равны ничему кроме себя самих. Иногда это позволяет сгенерировать в два раза более оптимальный код.Код: Выделить всё
int x=2; int y=2; int * __restrict z=&x; int * __restrict t=&y;
2B OR NOT(2B) = FF
А ну да, прогнал, проглядев функции. Но в случае указателей это не имеет значения, так как они могут быть не равны. И хотя поддерживается и , но это можно обработать как особый случай, отдельно от декларации ссылки как синонима переменной.
Код: Выделить всё
int x;
int y;
int &f1()
{
return x;
}
int &f2()
{
return y;
}
...
int &z=f1();
int &t=f2();
Знал бы ты, как медленно он у меня работает. Я и поиграть успеваю в две игры, и японский кросворд разгадать, и кино посмотреть за время компиляции. И время компиляции - не повод утверждать, что все вдруг занялись её оптимизацией в ущерб времени исполнения. Вот приложения должны работать быстро, иначе люди будут кидаться. Молотками по компам.Компилятор должен работать быстро, иначе люди будут сердиться и плеваться.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Да, у нас на форуме один Сионист имеет опыт компиляции С++ проектов.Знал бы ты, как медленно он у меня работает. Я и поиграть успеваю в две игры, и японский кросворд разгадать, и кино посмотреть за время компиляции.
Фортран компилируется быстро и проблем с синонимами не имеет, отчего генерирует очень быстрый код для работы с многомерными массивами. Поэтому в научных вычислениях обычно используют именно его. По крайней мере, использовали до недавнего времени.И время компиляции - не повод утверждать, что все вдруг занялись её оптимизацией в ущерб времени исполнения.
2B OR NOT(2B) = FF
Оказывается я фортран в серьёзных проектах использовал. Интересно как, если я его толком не знаю? А если серьёзно, то у меня пока нет завершённых проектов на c++, имеющих какое либо иное назначение кроме научных вычислений. Для остального бейсик, паскаль и внимание... фортран! Спектрумовскеий бейсик проблем с синонимами не имеет, но даже в мануэле к нему пишут, что бейсик-программы исполняются в 50 раз медленнее, чем компилированные и даже не уточняется, с какого языка компилированные, видимо имеется ввиду некая усреднённая скорость исполнения программ. Не мифическая проблема синонимов влияет на скорость исполнения, а совсем другие факторы. Во-первых интерпретация текста медленнее исполнения натива. Но даже в мануале к балсту, а это оптимизирующий компилятор бейсика, обещано ускорение по сравнению со встроенным интерпретатором всего в 36 раз, а не в 50. Тормоза также появляются, когда до рантайма доживает таблица переменных. Плохое решение, но возможное, если кто задастся целью сделать пессимизирующий компилятор, то может быть именно так компилируемые им программы и будут тормозить. Но хорошие компиляторы так не делают, не зависимо от языка. Следующие факторы: избыточные проверки и не только на выход за пределы массива и переувлечение вариэнтом и подобными ему типами. Дальше идёт переувлечение действительными типами. На спектрумовском бейсике нет целого типа, так что даже счётчики всех циклов приходится юзать действительные. Инкрмент быстрее, чем , так как икремент выполняется за одну операцию, а - это сначала копирование i в буфер, потом увеличение его на единицу операцией ADD, требующей к тому же загрузки лишнего операнда, а потому могущей выполняться медленнее, чем INC, а потом копирование суммы в I. И здесь приходим к вопросу о качестве оптимизатора в компиляторе, если он способен заменить всю цепочку на INC, то скорость исполнения от отсутствия в языке инкремента не пострадает, а если нет, то пострадает. На c++ же уже есть готовый инкремент. тоже быстрей, чем , так как - это просто ADD, а - ADD с двумя копированиями. Но это различие проявляется только если x уже хранится в регистре, так как регистр - тот самый буфер. И опять таки одно может быть оптимизировано до другого компилятором. То же самое относится к декременту и составному оператору вычитания и присваивания. также быстрей, чем , а - чем , а если x и o целые, то даже чем и тоже из-за двух копирований, но оптимизируется до CODE]x:=x*n;[/CODE] оптимизируется до , а и - до . Опять таки если в языке уже есть составные операторы, то можно их сразу использовать, а если их нет, то остаётся полагаться на оптимизатор неизвестного качества. В последнюю очередь назову переувлечение указателями, из перечисленного оно влияет меньше всего. Ив последнюю - не возможность изменения локальных копий параметров и операднов, которые не были объявлены как изменяемые, то есть через которые нельзя вернуть значения. Тот же факториал на одну операцию быстрей, чем . А если язык не допускает таких вольностей в отношении локальных копий? Если любой параметр эквивалентен или переданному по обычной ссылке, или переданному по константной ссылке? И это только то, валяется на "поверхности". А ведь есть и нюансы, известные только разработчикам оптимизаторов и не факт, что оптимизатор в компиляторе того же фортрана одного качества с плюсовым, это разные программы, писанные разными программистами. Кстати, явные именованные ссылки могут быть хоть как то полезны ровно в двух случаях:
1. Параметры и операнды.
2. Присваивание переменной значения функции, возвращающей ссылку, или такого же операнда в тех случаях, когда требуется зафиксировать адрес, к которому происходит обращение, но функция/оператор может возвращать ссылку на новую функцию/переменную при каждом обращении.
В остальных случаях они безтолку усложняют текст.
Может быть любая ссылка - надстройка над указателем. Стандарт требует, чтоб любая ссылка вела себя, как если бы была надстройкой над указателем (хотя чёрт его знает, может и другими словами это формулирует). Но стандарт не требует именно такой реализации абсолютно всех ссылок.
Код: Выделить всё
i:=i+1;
Код: Выделить всё
i:=i+1;
Код: Выделить всё
x+=y;
Код: Выделить всё
x:=x+y;
Код: Выделить всё
x+=y;
Код: Выделить всё
x:=x+y;
Код: Выделить всё
r*=n;
Код: Выделить всё
x:=x*n;
Код: Выделить всё
x/=o;
Код: Выделить всё
x:=x/o;
Код: Выделить всё
x:=x div o;
Код: Выделить всё
r*=n;
Код: Выделить всё
r*=n;
Код: Выделить всё
x:=x/o;
Код: Выделить всё
x:=x div o;
Код: Выделить всё
x/=o;
Код: Выделить всё
unsigned long long int f(unsigned short int n)
{
unsigned long long int r;
for (r=1; n>0; --n)
{
r*=n;
}
return r;
}
Код: Выделить всё
unsigned long long int f(unsigned short int n)
{
unsigned long long int r;
unsigned short int i;
for (r=1, i=n; i>0; --i)
{
r*=n;
}
return r;
}
1. Параметры и операнды.
2. Присваивание переменной значения функции, возвращающей ссылку, или такого же операнда в тех случаях, когда требуется зафиксировать адрес, к которому происходит обращение, но функция/оператор может возвращать ссылку на новую функцию/переменную при каждом обращении.
В остальных случаях они безтолку усложняют текст.
Может быть любая ссылка - надстройка над указателем. Стандарт требует, чтоб любая ссылка вела себя, как если бы была надстройкой над указателем (хотя чёрт его знает, может и другими словами это формулирует). Но стандарт не требует именно такой реализации абсолютно всех ссылок.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Мог бы просто в одну строчку написать "Я читал про спектрумовский бейсик, но не читал про static single assignment form", короче бы вышло.
Да, и чтение-запись в регистры не дает 50-кратного ускорения над ячейками памяти в стеке. Часто используемые ячейки памяти хранятся в кеше L0, и вершина стека с локальными переменными попадает именно туда. У меня есть виртуальная машинка, в ней в режиме интерпретации каждому регистру соответствует ячейка в массиве. Виртуалка умеет выделять функции по тому куда часто делают call и компилирует их в нативный код. При этом ячейки памяти с псевдорегистрами заменяются на настоящие нативные регистры. Ускорения в 50 раз не происходит. В Debug компиляции ускорение в 18 раз, в Release режиме интерпретатор по видимому оптимизируется очень хорошо, и ускорение всего в 6 раз. Проблема спектрумовского бейсика скорее всего в том что на Z80 не было аппаратного ускорителя плавающей точки, и для каждого инкремента переменной вызывалась довольно нетривиальная подпрограмма из ПЗУ, которая сначала денормализовала экспоненту, потом прибавляла к мантиссе единичку, а потом нормализовала экспоненту обратно. Хотя нет, кажется припоминаю что там был union в котором либо int16 либо плавающая точка.
Да, и чтение-запись в регистры не дает 50-кратного ускорения над ячейками памяти в стеке. Часто используемые ячейки памяти хранятся в кеше L0, и вершина стека с локальными переменными попадает именно туда. У меня есть виртуальная машинка, в ней в режиме интерпретации каждому регистру соответствует ячейка в массиве. Виртуалка умеет выделять функции по тому куда часто делают call и компилирует их в нативный код. При этом ячейки памяти с псевдорегистрами заменяются на настоящие нативные регистры. Ускорения в 50 раз не происходит. В Debug компиляции ускорение в 18 раз, в Release режиме интерпретатор по видимому оптимизируется очень хорошо, и ускорение всего в 6 раз. Проблема спектрумовского бейсика скорее всего в том что на Z80 не было аппаратного ускорителя плавающей точки, и для каждого инкремента переменной вызывалась довольно нетривиальная подпрограмма из ПЗУ, которая сначала денормализовала экспоненту, потом прибавляла к мантиссе единичку, а потом нормализовала экспоненту обратно. Хотя нет, кажется припоминаю что там был union в котором либо int16 либо плавающая точка.
Когда функция или метод класса с внешней линковкой возваращают ссылку не существует иного способа кроме ее реализовать кроме как при помощи передачи адреса. Если же возможно ее заинлайнить, то можно промежуточную ссылку выкинуть и работать непосредственно со значением на которое она ссылается. Но и указатель тоже можно выкинуть в таком случае.Стандарт требует, чтоб любая ссылка вела себя, как если бы была надстройкой над указателем
2B OR NOT(2B) = FF
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Очень здраво рассуждаешь, Absurd. Причём один комментарий лучше другого. Давно уже хотел репутацию апнуть тебе. Вот добрались руки 

Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.