Beginning
Aug 30 2007, 15:00
Учусь работать в IAR. Много вопросов. Как обозначить глобальную переменную, что бы она была видна в других подлинковачных файлах.
Как обозначить переменную, что бы она лежала по конкретному адрессу.
jorikdima
Aug 30 2007, 15:08
тут не иар, тут с надо учить.
1. прочитайте про extern
2. прочитайте доку по линкеру
На первый вопрос уже ответели, по поводу как разместить по конкретному адресу
неинициализируемая меременная
#pragma location = адрес
__no_init int ttt;
или
__no_init int ttt @адрес;
константа
#pragma location = адрес
const int ttt = 123;
или
const int ttt @адрес = 123;
zltigo
Aug 30 2007, 15:33
Цитата(Beginning @ Aug 30 2007, 18:00)

Как обозначить глобальную переменную, что бы она была видна в других подлинковачных файлах.
Абсолютно так же как в любимом, как я слышал, Вами всей душой Keil и вообще в
любом компиляторе 'C'.
P.S.
Место этого вопроса не в теме по АРМ. Перенес.
P.P.S.
В 'C' все глобальные переменные видны снаружи по умолчанию, если специально не ограничивать область видимости, но мне что-то подсказывает, что вопрос был не об этом.....
Beginning
Aug 30 2007, 16:37
Где в настройках IAR включить, что бы внешние переменные были глобальными, т.е виделись во всех файлах.
zltigo
Aug 30 2007, 16:52
Цитата(Beginning @ Aug 30 2007, 19:37)

Где в настройках IAR включить
Повторяю - нигде. Они таковые по умолчанию и "галочками" естественно не отключаются. Тут уже было высказано предположение о том, что надо почитать про extern. Читать в любой книжке по "C".
Повторяю по "C" а не по Keil, IAR, GNU, Rowley, ибо это фича языка а не особенность компилятора.
Что касается допонительного вопроса по размещению чего-то по конкрктному адресу, то лучше этого не делать никогда.
А если уж сильно надо, то пользоватся надязыковыми средствами типа линкера. И только в наикрайнейшем случае следует пользоватся уникальными наворотами конкретного компилятора, прочитав документацию на конкретный компилятор. Что каксается IAR, то это зависит от версии. В 5.10,
например, похерили (ну и наверное правильно) инициализацию

что на самом деле ознает, что похерили все, ибо просто обращение по конкретному адресу не требует искуственных наворотов к языку. Правда линкер у них пока сырой (или я не врубился совсем), что связывает руки.
Beginning
Aug 30 2007, 17:49
Про EXTERN знаю. Я писал много под AVR. Гарвардская архитектура. Там три сегмента FLASH, ROM, DATA использовал, и всё было в шоколаде (CodeVisionAVR C Compiler). Глобальные переменные были видны во всех файлах, и не было проблем с дополнительными манипуляциями. Сейчас под ARM пишу, Фон Неймовская архитектура, и много вопросов появляется, наверняка являющиеся раздражительными и недостойными для местных гуру. А по конкретному адресу надо потому, что программа из внешней ROM работает, а переменная должна во внешней flash сохранятся.
Кстати хотел Вам zltigo ответить, хотя Вы всячески пытаетесь меня уязвить в неграмотности, но ладно, Вы мне отвечаете на вопросы, на поиск ответов на которые сейчас просто НЕТ ВРЕМЕНИ! Горит проект. И за это Вам спасибо. Так вот что такое listing, как не удивительно, я тоже знаю. Я говорил за удобство. В других оболочках (Keil, Cvision) мне было удобно работать так, а не просматривать listing. А в IAR я такой возможности, не обнаружил, поэтому и спросил.
zltigo
Aug 30 2007, 18:14
Цитата(Beginning @ Aug 30 2007, 20:32)

Про EXTERN знаю. Я писал много под AVR. Гарвардская архитектура. Там три сегмента FLASH, ROM, DATA использовал, и всё было в шоколаде (CodeVisionAVR C Compiler). Глобальные переменные были видны во всех файлах
Цитата
Вы хоть поняли, что написали? Незнаю, что Вы там писали, но сие абсолютно платформенно независимая вещь.
наверняка являющиеся раздражительными и недостойными для местных гуру
Эти вопросы достаточно обычны, а вот что мне несколько не понравилось, так это Ваше совершенно ничем не спровоцированное выступление за один из компиляторов с нелестными эпитетами по поводу другого. Из которого вроде-бы следовало, что Автор всех собак съел на этом, хотя и не приступал к этой закуске

. Так что, простите, я на все через эту призму смотрю.
Цитата
А по конкретному адресу надо потому, что программа из внешней ROM работает, а переменная должна во внешней flash сохранятся.
О господи! Про указатели прочитайте, да?
Beginning
Aug 30 2007, 18:25
Да причём сдесь компилятор. Я же вам говорил, что мне по-барабану какой компилятор. Я за среду говорил. За её возможности в симуляции и отладке и редакторе, да.
rezident
Aug 30 2007, 18:46
Цитата(=F8= @ Aug 30 2007, 21:33)

константа
#pragma location = адрес
const int ttt = 123;
или
const int ttt @адрес = 123;
Насчет последнего выражения с константой по-моему вы ошибаетесь. В последних версиях IAR выкинула такую конструкцию, чтобы более точно соответствовать стандарту. Где-то здесь на форме недавно постили выдержку из описания релиза по этому поводу. Примерный смысл такой: квалификатор const не обязывает к тому, что переменная с этим квалификатором обязана во Flash находиться. const указывает лишь на то, что это переменная не модифицируется.
zltigo
Aug 30 2007, 19:53
Цитата(Beginning @ Aug 30 2007, 21:25)

..мне по-барабану какой компилятор.
Да, это заметно

.
Ладно, все - больше не буду.
Цитата(rezident @ Aug 30 2007, 21:46)

В последних версиях IAR выкинула такую конструкцию...
Выкинули инициализацию. Осталось некоторая видимость ввиде указания адреса, что уже совершенно ненужный прибамбас, ибо штатными 'C' средствами решается.
Цитата
, чтобы более точно соответствовать стандарту
ну стандарт этого не определяет и не запрещает. Формат объектника на ELF поменяли а это
(как и исчезновение выкидывания неиспользуемых функций при линковке объектников) просто последствия. Зато теперь чужими линкерами и библиотеками можно пользоватся, что крайне неплохо.
Цитата
квалификатор const не обязывает к тому, что переменная с этим квалификатором обязана во Flash находиться. const указывает лишь на то, что это переменная не модифицируется.
Ну перебор

, естественно не для случая, когда явно указан адрес расположения переменной.
Beginning
Aug 31 2007, 12:57
У меня есть функция обработки векторного прерывания IRQ таймера (IAR). Как мне обозначить функцию, чтобы компилятор корректно выходил из этой функции. Т.е со сменой режима IRQ->USER. Или в конце функции какой то оператор ставить надо.
Beginning
Aug 31 2007, 17:07
В IAR в симуляторе перефирийные регистры работают? Настраиваю таймер, а он не инкрементируется при симуляции.
Сергей Борщ
Aug 31 2007, 21:22
Цитата(Beginning @ Aug 31 2007, 20:07)

В IAR в симуляторе перефирийные регистры работают? Настраиваю таймер, а он не инкрементируется при симуляции.
Нет. Это описано в документации, как и ответ на ваш предыдущий вопрос.
Beginning
Aug 31 2007, 22:14
Какие все умные, всё в документацию тычут. Много слов пишут, вместо того чтобы написать два слова: __irq и VICVectAddr=0. У меня сейчас просто нет времени искать, потерял пол дня на поиск вот этого.
one_man_show
Sep 1 2007, 05:32
Уважаемый Beginning, пожалуйста не горячитесь. Почему Вы думаете, что только у Вас нет времени искать? Хорошо, что Вы иногда хоть благодарите за ответы, иначе получилось бы, что Вы работаете, а все остальные ждут Ваших вопросов, занимаются фигней и не удосуживаются дать конкретный ответ.
Удачи Вам в текущем срочном проекте! Мы Вас все прекрасно понимаем, так как многие из нас были, а кто-то и сейчас, находятся в цейтноте.
Beginning
Sep 1 2007, 08:59
Да ладно, ни на кого зла не держу. Всё понимаю. Вот, например zltigo вывело то, что я нелестно о IAR отозвался (хотя он меня неправильно понял), а меня немного вывело то, что меня все вдруг начали считать неучем и нежелающим искать ответы. Я всегда ищу ответы САМ. Просто сейчас особый случай, ни сегодня, завтра проект сдавать. Вот и использую все возможные варианты. И в форум вопрос кину и параллельно сам ищу. Просто возникает множество мелких элементарных вопросов, которые просто требуют ответа типа ”да/нет”, и движешься дальше, решая уже сложные алгоритмические задачи. Ан нет, надо каждый раз спотыкаться, прекращать основную работу и искать, искать… Вообщем ещё раз скажу всем спасибо, кто помог, и тем кто возможно ещё поможет.
Цитата(Beginning @ Sep 1 2007, 11:59)

zltigo вывело то, что я нелестно о IAR отозвался
Повторяю. Отнюдь не это, а то, что Вы своими оценками превосходства одного из компиляторов, с походя опусканием другого, неверно спозиционировали свой уровень знаний и навыков. Что и привело к диссонансу между вопросами и ответами. IAR мне не брат и не кум - никакого особого пиетета я не испытываю, просто пользуюсь, как впрочем и еще тремя компиляторами, в повседневной жизни. А документация у IAR вполне хороша, систематизирована и поиск по PDF работает много быстрее, нежели вопрос-ответ в форуме.
Сергей Борщ
Sep 1 2007, 09:14
Цитата(Beginning @ Sep 1 2007, 11:59)

И в форум вопрос кину и параллельно сам ищу.
Help->C/C++ compiler reference->Search->"irq" Search->"interrupt". Это сложно? Это занимает полдня? Тогда не удивительно, что <<завтра проект сдавать, а у меня “конь не валялся”>> и я в шоке, насколько нетривиальные вопросы нас еще ожидают.
P.S. Там есть еще папка examples в директории компилятора.
Beginning
Sep 1 2007, 09:48
N что __irq нашёл почти сразу. Вторая часть вопроса отняла время. Слушайте, никого не застовляю мне отвечать. Нихотите не надо. Спорить тоже не буду, времени нет. Да и топик вроде, как в "... для чайников" находится. И почему это вас всё так удевляет?
Beginning
Sep 1 2007, 19:54
Какую библиотеку в IAR для ARM надо подключить чтобы можно было использовать itoa (int->str)
rezident
Sep 1 2007, 21:09
Цитата(Beginning @ Sep 2 2007, 01:54)

Какую библиотеку в IAR для ARM надо подключить чтобы можно было использовать itoa (int->str)
ИМХО stdlib.h, но замечу, что itoa не является стандартной функцией Си, т.е. не включена в стандарт ANSI C. Стандартной функцией подобного преобразования является sprintf.
Beginning
Sep 1 2007, 22:00
В IAR нет itoa. Использую во это:
Цитата
uint8* itoa(int val, int base)
{
static uint8 buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
};
Вопрос. Как мне обозначить подключаемый asm файл с startup чтобы IAR его использовал, а не брал свой. А то возникает ошибка, мол два куска кода ссылаются на одни и те же адреса.
Цитата(Beginning @ Sep 2 2007, 01:00)

В IAR нет itoa. Использую во это:
Это не itoa(), ни по формату, ни по отсутствию обработки отрицательных значений. Посему обозвать другим словом. При отрицательных значениях - глюки. Возвращаемое значение указатель на char а не на unsigned char, поскольку речь идет о строке. Последний оператор ; - лишний. --i вместо i--, естественно аболютно не принципиально, но заставляет читающео думать о каких-то наихитрейших хитростях. Вынесение присвоения i из for, тоже ничем не обосновано и сбивает процесс чтения. Значения 0 обычно как '0' печатают а не 'ничего'.
Проверка i - лишняя, ибо буфер под строчку достаточной длинны.
Код
char *ulongtoa( unsigned long val, int base )
{
static char buf[32+1] = {0};
int i = 32-1-1;
do
{ buf[i--] = "0123456789abcdef"[val % base];
val /= base;
}
while( val );
return( &buf[i] );
}
Цитата
Как мне обозначить подключаемый asm файл с startup чтобы IAR его использовал, а не брал свой.
"Cвой" он естественно не берет, если явно не указано линковать, например, объектник - разбирайтесь с 'галочками'.
Цитата
А то возникает ошибка, мол два куска кода ссылаются на одни и те же адреса.
????
Beginning
Sep 2 2007, 14:45
Есть 32-bit переменная. И есть 8-bit переменная. Какая конструкция используется (кроме сдвига) для копирования 8bit в разные части 32-bit переменной. Т.е в первый, второй, или третий байт.
Общий случай элементарные логические операции:
Код
my_long = my_byte;
my_long |= (long)my_byte << 8;
...
my_long |= (long)my_byte << 24;
А конкретный эффективный вариант зависит от того, как хранятся байтовые переменные.
Beginning
Sep 2 2007, 15:28
Народ может, кто алгоритм подкинет, если есть, а то уже голова пухнет и не хочет работать. В общем, есть dallas таймер. Он вазвращает 32bit число – количество секунд. Так вот его надо раздраконить в минуты(char), часы(char), дни(char), месяц(char), год(short).
Спасибо

. Знал, что есть такая (раньше как-то видел), но забыл. На 8bit машине редко используется.
Цитата(Beginning @ Sep 2 2007, 18:28)

Он вазвращает 32bit число
Нежелание ознакомится с языком, начинает превышать все разумные пределы
localtime() или gmtime().
Beginning
Sep 2 2007, 16:11
Ну почему же нежелание. Не было б желания, вообще не писал бы и не искал. Вот вы мне подсказали направление, где искать. Сейчас сижу, изучаю библиотеку time.h. Правда в help IAR по этим функциям оставляет желать лучшего, некоторые вообще, без каково либо описания, но ничего разберёмся.
Цитата(Beginning @ Sep 2 2007, 19:11)

изучаю библиотеку time.h
Главное слово
time какое незнакомое

ну ни в жисть не догадаться поискать

Цитата
Правда в help IAR по этим функциям оставляет желать лучшего
Ну как-бы с одной сторны это не дело компилятора справочник по стандартному 'С' содержать, а так действительно поганенький

.
Возьмите книжку, просто книжку.
У меня к моей IDE подключены пяток "C" хелпов

на выбор и никакких проблем.
Из бесплатно-доступных приличный чисто языковый у OpenWatcom.
Beginning
Sep 2 2007, 18:12
Я 24 часа на ногах в монитор смотрю. У меня в голову не то что, бы слово time не приходит, я уже частенько ловлю себя на мысле что, тупо смотрю в монитор и ничего не делаю.
Beginning
Sep 3 2007, 19:04
Помогите найти засаду. Использую функцию localtime().
time_t n_sec;
struct tm *tm_p;
n_sec=time_;
tm_p = localtime(&n_sec);
Так вот. Код компилируется, но когда зашивается в проц, то проц виснет. Может какие специальные настройки надо. Она вроде кучу использует.
Сергей Борщ
Sep 3 2007, 21:15
Цитата(Beginning @ Sep 3 2007, 22:04)

Так вот. Код компилируется, но когда зашивается в проц, то проц виснет. Может какие специальные настройки надо. Она вроде кучу использует.
n_sec=1234;
tm_p = localtime(&n_sec);
И в симулятор, по шагам. Этот код не работает с периферией, поэтому отсимулироваться должен на "хорошо" и "отлично".
Сергей Борщ
Sep 4 2007, 07:34
Цитата(Сергей Борщ @ Sep 4 2007, 00:15)

И в симулятор, по шагам.
Последовал своему совету. Функция действительно интересная. Она требует наличия сегмента HEAP и возвращает указатель на структуру. Казалось бы, она выделяет динамическую память. Ан нет, она возвращает указатель на статически выделенную область памяти в DATA_Z, а HEAP не используется совсем. Поэтому, если интуитивно попытаться осводить память под возвращенное значение (delete tm_p) можно получить крушение всей памяти. Угадал?
Beginning
Sep 4 2007, 09:01
В симуляторе в функцию входит и выходит (как там винипух говорил). Но при зашитии в проц он фиснит. Т.е. код выолняется нормально, но когда доходит до localtime() зависает. Когда просматривал asm функции, то всречал редкие коментарии вставленные IAR типа "malloc" или "heap".
delete tm_p - это не использовал
Определяю структуру в main.c как глобальную:
struct {
uint8 a[6];
uint8 b[5];
uint8 c[4];
uint8 d[3];
uint8 e[3];
uint8 f[6];
} data;
В другом файле хочу использовать её:
extern strucr data;
data.a[0]=10;
Возникает предупреждение:
Warning[Pe1000]: a storage class may not be specified here E – на вот это ”extern strucr data;
”
И далее ошибки:
Error[Pe020]: identifier "data" is undefined
В чём засада?
Пробывал обычный int x; в другом файле extern int x; Всё прокатывает. Struct воспринимается же, тоже как переменная. Но не работает.
Сергей Борщ
Sep 4 2007, 09:50
Цитата(Beginning @ Sep 4 2007, 12:01)

В симуляторе в функцию входит и выходит (как там винипух говорил). Но при зашитии в проц он фиснит. Т.е. код выолняется нормально, но когда доходит до localtime() зависает.
Ну, возможно ваша версия использует heap. Вы еще где-то используете malloc, new и т.д.? Если нет, сколько памяти вы выделили под сегмент HEAP? Возможно зависание происходит из-за невозможности выделить достаточно памяти. Хотя тогда должно и в симуляторе виснуть. Я все же склонен считать, что чудес не бывает и "зависание" происходит по причине нехватки памяти, например - стека.
Цитата(Beginning @ Sep 4 2007, 12:01)

Определяю структуру в main.c как глобальную:
А ведь говорили - внимательно прочитайте учебник про extern. Когда вы компилируете другой файл, компилятор понятия не имеет ни о main.c, ни о том, какие поля есть у описанной там структуры.
Цитата(Beginning @ Sep 4 2007, 12:01)

Возникает предупреждение:
Warning[Pe1000]: a storage class may not be specified here E – на вот это ”extern strucr data;
”
strucr вместо struct.
Цитата(Beginning @ Sep 4 2007, 12:01)

И далее ошибки:
Error[Pe020]: identifier "data" is undefined
В чём засада?
Пробывал обычный int x; в другом файле extern int x; Всё прокатывает.
Потому что int, char, float, указатели - это встроенные типы. А структуры - это типы, определяемые пользователем. Попробуйте так:
"в другом файле":
extern struct {
uint8 a[6];
uint8 b[5];
uint8 c[4];
uint8 d[3];
uint8 e[3];
uint8 f[6];
} data;
Потом когда захотите внести изменение в эту структуру и полезете по всем файлам искать и править ее объявление - прочитайте в букваре по С про заголовочные файлы.
Цитата(Сергей Борщ @ Sep 4 2007, 10:34)

Функция действительно интересная.
Она много еще чего требует - установки временной зоны, правил перехода летнее/зимнее время ...
Попробуйте для начала gmtime(). А потом уже на локальное переходить.
Beginning
Sep 4 2007, 11:41
Цитата
strucr вместо struct.
Очепятка. В исходниках верно написано.
Beginning
Sep 5 2007, 07:09
Попробывал использовать Гринвичское время gmtime(), всё заработало наура.
Цитата(Beginning @ Sep 5 2007, 10:09)

Попробывал использовать Гринвичское время gmtime(), всё заработало наура.
Ну если лето/зима/временная_она не нужны, что маловероятно, то пользуйтесь. В противном случае разбирайтесь с IARовской _Tzoff(void), которая отвечает за все вышеперечисленное и теми параметрами которыми она пользуется.
Я лично с начала 90x, когда передомною возникла такая проблема для встоенной системы ушел на "свою" сделаннаю по мотивам борландовской библиотечной, но со статическим tm и 'универсальным' 16bit идентификатором летнего времени
[StartMonth]
[EndMonth]
[Style]
[ChangeHour]
задаваемым в конфигурации.
Кстати, совет - системные часы должны идти по Гринвичу, а не по локальному времени, как это в свое время сделали недоумки( это не ругательство это констатация факта) из MS.
Beginning
Sep 5 2007, 11:50
А что вы имели под "лето/зима/временная_она"? В смысле летнее/зимнее время. Мне оно не нужно. На час вперёд и назад можно руками перевести. А почем, мне надо использовать в системе именно время по Гринвичу? Это автономная система с часами реального времени (возвращает int32 – количество секунд). Получил с этих часов время, отправил в gmtime() и забрал полученные часы, дни, месяцы и др. из структуры. Или здесь где-то засада зарыта?
Цитата(Beginning @ Sep 5 2007, 14:50)

А что вы имели под "лето/зима/временная_она"? В смысле летнее/зимнее время. Мне оно не нужно. На час вперёд и назад можно руками перевести.
Ну не нужно, так не нужно (хотя не красиво ) тогда часы идут по локальному времени а находитесь Вы все равно где, пусть и в Гринвиче

.
Цитата
Или здесь где-то засада зарыта?
Если Вы живете по Гринвичу/UTC называя это своим локальным временем, то никаких проблем нет.
Проблемы с зонами и переходами лето/зима. В случае часов по гринвичу они НИКОГДА не переставляются и вычисляется только поправка. В случае системных часов по локальному времени ВАМ ПРИДЕТСЯ ПЕРЕСТАВЛЯТЬ ЧАСЫ, что само по себе может быть неудобным и в придачу возникают неопределенности, например, Вы включили устройство в 2:30 минут (по системныи часам) в день перехода веремени - который час? Ответ не возможен без дополнительного знания о том какое время лето/зима сейчас часы показывают.
Beginning
Sep 6 2007, 07:35
Как-то странно работает float.
Например:
float f;
int x=56;
f= 4567/x;
// f=81,5535…
f*=100;
//f должен быть равен 8155,35…
x=f;
и получаем х=8100;
Вобщем вот это “f*=100;” похоже умножает только целую часть.
Мне надо получить дробную, в чём засада.
А что, интересно, должно было получиться, если
делить int на int ?
Код
float x=56;
Beginning
Sep 6 2007, 13:11
const uint8 x[4][4]= { (1,2,3,4),
(1,2,3,4),
(1,2,3,4),
(1,2,3,4)
};
Почему на это выражение ругается.
Выдаёт:
Error[Pe057]: this operator is not allowed in a constant expression
float x=56;
Вообще то логично.
Код
const uint8 x[4][4]= { (1,2,3,4),
(1,2,3,4),
(1,2,3,4),
(1,2,3,4)
};
Чем дальше в лес, тем больше дров

. Может стоит хоть книжку по С прочитать? Компилятору
не по барабану круглые или фигурные скобки.
Beginning
Sep 6 2007, 13:46
Вырезка из книги Керинан и Ричи:
STATIC INT DAY_TAB[2][13] = {
(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
(0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
};
Я использовал эту конструкцию в CodeVision, и не было никаких ошибок.
И кому здесь по барабану?
Цитата(Beginning @ Sep 6 2007, 16:46)

И кому здесь по барабану?

Правильному компилятору не по барабану мусорные круглые скобки. Либо уберите их совсем и неявно инициализируйте многомерный массив одномерным,
Код
const uint8 x[4][4]= { 1,2,3,4,
1,2,3,4,
1,2,3,4,
1,2,3,4
};
либо инициализируйте многомерные массивы, как положено - фигурными скобками.
Код
const uint8 x[4][4]= { {1,2,3,4},
{1,2,3,4},
{1,2,3,4},
{1,2,3,4}
};
Цитата
Вырезка из книги Керинан и Ричи:
Компиляторы с опцией компилировать в стиле K&R уже почти вымерли и слава богу, ибо есть С99.
Сергей Борщ
Sep 6 2007, 14:11
Цитата(zltigo @ Sep 6 2007, 11:02)

или f= 4567.0/x; В данном примере все равно, но если перед этим с x производятся какие-то действия, то разница будет.
Beginning
Sep 6 2007, 14:12
Какой же это правильный компилятор, если не по ANSI C делает. А вы, прежде чем в книги отсылать, лучше бы попробовали сами. На конструкцию предложенною вами у компилятора вообще аллергия:
const uint8 dd[4][]{ {1,2,3,4},
{1,2,3,4},
{1,2,3,4},
{1,2,3,4} };
Error[Pe098]: an array may not have elements of this type
Error[Pe065]: expected a ";"
Я к стати эту конструкцию пробывал, ещё до обсуждения.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.