Не линкуется что значит
Линкануть
Линкануть – происходит от английского слова link, что переводится как ссылка или указатель. Что такое линкануть? Это отправить куда-нибудь определённую ссылку.
Термин употребляется в двух значениях.
1. Ссылка на сайт или какой-то интернет-ресурс. Например, сидя в RaidCall, вы можете попросить скинуть вам ссылку на гайд или форум. Тогда человек скопируют её с адресной строки браузера и отправит в чат RC. При нажатии вы сразу выйдете на нужный сайт. Также для вставки можно воспользоваться сочетанием клавиш Ctrl+V.
2. Линк предмета, части игровой экипировки и так далее. Когда вы собираетесь продать какой-то предмет в игре, то прежде вам необходимо показать его покупателю. Когда торгуете через аукцион, то все свойства и характеристики видны, но за выставление на аук берется комиссия, потому продавать напрямую выгоднее. Передавать для демонстрации вещь потенциальному покупателю не только долго, но и опасно – вам могут не заплатить. Вот тут на помощь и приходит линкование предмета в чат.
В разных проектах способы отличаются, однако наиболее распространенный – зажать клавишу Shift и левой кнопкой мыши щелкнуть по вещи, что находится у вас в рюкзаке. В чате появится название, возможно окрашенное в цвет, характеризующий качество (например, синие наручи). Если другой человек наведет мышь на него или кликнет по ссылке, то перед ним появится табличка, где прописаны все статы этой вещи.
Кидать ссылки можно не только на части экипировки, но и на многие другие предметы:
В последнем случае вы делаете примерно то же, что и с содержимым вашего рюкзака или склада, только предварительно открываете карту мира и потом кликаете в нужную точку.
Линкануть в игре можно почти все, даже профессии и навыки. Но мобов, боссов или персонажей обычно нельзя. Во-первых, параметров очень много, а во-вторых, внутреннее содержание (распределение статов, их значения и так далее) – личное дело каждого и почти тайна.
Линковать
Дополнительный поиск Линковать
На нашем сайте Вы найдете значение «Линковать» в словаре Словарь компьютерного жаргона, подробное описание, примеры использования, словосочетания с выражением Линковать, различные варианты толкований, скрытый смысл.
Первая буква «Л». Общая длина 9 символа
Угадайте следующее слово, по смыслу схожее с нижеприведенными
Введите следующее слово: 7 букв
Добрый день, меня зовут Ирина. Нас заинтересовал Ваш сайт. Мы хотели бы с вами поработать на взаимовыгодных условиях. К примеру мы бы хотели разместить статью или новость на вашем сайте про наш сайт. Скажите это возможно? Какие еще варианты у вас ест..
Поздравляем профессора-сексолога Щеглова Л. М. с присвоением ему звания «попса1 от психологии» за вклад в развитие жанра психологического мыла. Признаки явления: плодовитая, пустопорожняя и назойливая. Отсутствие фамилии в Российском индексе научного..
Линковка в Linux
Table of Contents
1 Ссылки
2 Линковка
Линковка это процесс компоновки различных кусков кода и данных вместе, в результате чего получается один исполняемый файл. Линковка может быть выполнена во время компиляции, во время загрузки (загрузчиком) и также во время исполнения (исполняемой программой). Раньше (конец 40-х) линковка выполнялась вручную, сейчас мы имеем программы линковщики (linkers), которые дают возможность динамической линковки разделяемых библиотек (shared libraries).
3 Основы
Пусть у нас есть два файла с кодом a.c и b.c. Чтобы скомпилировать эти два файла при помощи GCC, мы вызываем следующий код
Это вызывает следующую последовательность:
Запустить препроцессор на файле a.c и сохранить результат в промежуточный файл a.i
Запустить компилятор на a.i и сгенерировать ассемблерный код в a.s
Запустить ассемблер на a.s и сгенерировать объектный файл a.o
Работа линковщика состоит в том, чтобы получить на вход сгенерированные объектные файлы a.o и b.o и сгенерировать из них финальный исполняемый файл a.out
После этого мы можем запустить наш бинарный файл ./a.out. Оболочка командной строки вызовет функцию загрузчика, которая скопирует код и данные из исполняемого файла a.out в память, затем передаст управление в начало программы. Функция загрузчик называется execve, она загружает код и данные исполняемых объектных файлов в память, затем запускает их выполнение, прыгая на первую инструкцию.
4 Линковщики и Загрузчики
Линковщики (linkers) и загрузчики (loaders) выполняют концептуально разные, но в целом похожие задачи:
В итоге, получается что загрузчик выполняет загрузку программ; линковщик выполняет symbol resolution; оба выполняют релокацию.
5 Объектные файлы
Компиляторы и ассемблеры генерируют перемещаемые объектные файлы (а так же разделяемые объектные файлы). Линковщики компонуют эти объектные файлы вместе и генерируют исполняемые объектные файлы.
6 ELF
Объектные файлы разнятся в разных ОС. Первые UNIX системы использовали формат a.out. Ранние System V использовали формат COFF (common object file format). Windows NT использует разновидность формата COFF, называемую PE (portable executable); IBM использует собственный формат IBM 360. Современные UNIX системы, такие как Linux и Solaris используют формат UNIX ELF (executable and linking format).
6.1 Заголовки Elf
7 Символы и адресация символов
Каждый перемещаемый объектный файл содержит таблицу символов связанные символы. В контексте линковщика представлены следующие виды символов:
Линковщик разрещает адресацию символов путём соотношения каждой ссылки на символ только к одному определению символу из таблицы символов.
8 Линковка статических библиотек
9 Релокация
После того как линковщик разрешил адресацию всех символов, каждый адресация символа ссылается ровно на одно определение символа. В этот момент линковщик запускает процесс релокации, состоящий из двух шагов:
Ассемблер при релокации создаёт секции .relo.text и .relo.data, в которых содержится информация как разрешить адресацию (адрес для обращения к символу). ELF содержит в секциях релокации следующие данные:
10 Динамическая линковка: разделяемые библиотеки
Статические библиотеки, описанные выше, имеют существенный недостаток. Например, возьмём стандартные функции printf и scanf. Они используются почти что в каждой программе. Пусть на системе запущено 50-100 процессов, каждый процесс содержит свою копию исполняемого кода printf и scanf — это существенный объём затраченной памяти. Разделяемые библиотеки в свою очередь направлены на исправление этого недостатка статических библиотек. Разделяемые библиотеки это объектные модули, которые могут быть загружены в память в момент исполнения программы и после слинкованы с программой. Разделяемые библиотеки (shared libraries) называют так же разделяемые объекты (shared objects). На большинстве систем UNIX они именуются с суффиксом .so; на системах HP-UX — с суфиксом .sl; на системах Microsoft они называются DLL. Чтобы собрать разделяемый объектный файл, компилятор надо вызывать со специальным флагом
Эта команда сообщает компилятору, что надо сгенерировать разделяемую библиотеку libfoo.so, собранную из объектный файлов a.o и b.o. Флаг -fPIC сообщает компилятору, что надо сгенерировать адресо-независимый код (position independent code — PIC). Теперь представим что объектный модуль bar.o зависит от a.o и b.o. В этом случае мы компилируем его так:
Эта команда создаёт исполняемый файл a.out, который будет линковаться с libfoo.so в момент загрузки. Здесь a.out не содержит в себе объектный модулей a.o и b.o, которые были бы включены в него, если бы мы использовали статическую линковку. Исполняемый файл просто содержит некоторую информацию о релокации и таблицу символов, которые позволяют адресоваться к коду и данным в libfoo.so и эта адресация будет разрешена в процессе исполнения (runtime). Таким образом, a.out это не совсем исполняемый файл, который имеет зависимость от libfoo.so. Исполняемый файл содержит секцию .interp, где содержится имя динамического линковщика (который сам является разделяемым объектом в системах Linux — ld-linux.so). Таким образом, когда исполняемый файл загружается в память, загрузчик передаёт управление динамическому линковщику. Динамический линковщик содержит некоторый код, который отображает пространство адресов динамических библиотек на пространство адресов испольняемой программы.
В конце работы динамический линковщик передаёт контроль исполняемой программе. С этого момента местоположение разделяемого объекта зафиксировано в памяти.
11 Загрузка разделяемой библиотеки из приложения
Разделяемая библиотека может быть загружена из приложения в любой момент выполнения. Приложение может обратиться к динамическому линковщику с просьбой загрузить и прилинковать динамическую библиотеку. Linux, Solaris и другие системы поддерживают различниые функции, которые могут быть использованы для динамической загрузки разделяемых объектов. В Linux это системные вызовы dlopen, dlsym, dlclose, используемые для загрузки разделяемого объекта, поиска символа в разделяемом объекте и для закрытия разделяемого объекта.
Внутренняя и внешняя линковка в C++
Представляем вам перевод интересной статьи, который подготовили для вас рамках курса «Разработчик C++». Надеемся, что она будет полезна и интересна для вас, как и нашим слушателям.
Сталкивались ли вы когда-нибудь с терминами внутренняя и внешняя связь? Хотите узнать, для чего используется ключевое слово extern, или как объявление чего-то static влияет на глобальную область? Тогда эта статья для вас.
В единицу трансляции включены файл реализации (.c/.cpp) и все его заголовочные файлы (.h/.hpp). Если внутри единицы трансляции у объекта или функции есть внутреннее связывание, то этот символ виден компоновщику только внутри этой единицы трансляции. Если же у объекта или функции есть внешнее связывание, то компоновщик сможет видеть его при обработке других единиц трансляции. Использование ключевого слова static в глобальном пространстве имен дает символу внутреннее связывание. Ключевое слово extern дает внешнее связывание.
Компилятор по умолчанию дает символам следующие связывания:
Поговорим сначала о двух простых концепциях, необходимых для обсуждения связывания.
Объявление VS. Определение
Кратко обсудим разницу между объявлением и определением символа: объявление (или декларация) говорит компилятору о существовании конкретного символа, и позволяет обращение к этому символу в случаях не требующих точного адреса памяти или хранилища символа. Определение говорит компилятору, что содержится в теле функции или сколько памяти нужно выделить переменной.
В некоторых ситуациях компилятору недостаточно объявления, например, когда элемент данных класса имеет тип ссылки или значения (то есть не ссылка, и не указатель). В то же время, разрешен указатель на объявленный (но неопределенный) тип, так как ему нужен фиксированный объем памяти (например, 8 байт в 64-битных системах), не зависящий от типа, на который указывает. Чтобы получить значение по этому указателю, потребуется определение. Также для объявления функции нужно объявить (но не определить) все параметры (не важно взятые ли по значению, ссылке или указателю) и возвращаемый тип. Определение типа возвращаемого значения и параметров необходимо только для определения функции.
Разница между определением и объявлением функции весьма очевидна.
С переменными все немного иначе. Объявление и определение обычно не разделяются. Главное, что это:
Однако, при инициализации и добавлении extern к объявлению, выражение превращается в определение и ключевое слово extern становится бесполезным.
В C++ существует концепция предварительного объявления символа. Это значит, что мы объявляем тип и имя символа для использования в ситуациях, не требующих его определения. Так нам не понадобится включать полное определение символа (обычно — заголовочный файл) без явной необходимости. Тем самым, мы снижаем зависимость от файла, содержащего определение. Главное преимущество — при изменении файла с определением, файл, где мы предварительно объявляем этот символ, не потребует повторной компиляции (а значит, и все прочие файлы его включающие).
Предположим, у нас есть объявление функции (называемое прототипом) для f, принимающее объект типа Class по значению:
Допустим, file.hpp содержится в 100 других файлах. И, допустим, мы меняем определение Class в class.hpp. Если вы добавим class.hpp в file.hpp, file.hpp и все 100 содержащих его файла будут должны перекомпилироваться. Благодаря предварительному объявления Class единственными файлами, требующими повторной компиляции, будут class.hpp и file.hpp (если считать, что f определен там).
Важное отличие объявления от определения состоит в том, что символ может быть объявлен много раз, но определен только однажды. Так вы можете предварительно объявить функцию или класс сколько угодно раз, но определение может быть только одно. Это называется Правилом Одного Определения. В C++ работает следующее:
Есть следующие файлы:
Препроцессор выдаст следующую единицу трансляции, которая затем передается компилятору:
Обсудив основы, можно приступить к связям. В целом, связь — это видимость символов для компоновщика при обработке файлов. Связь может быть либо внешней, либо внутренней.
Когда символ (переменная или функция) обладает внешней связью, он становится видимым компоновщикам из других файлов, то есть “глобально” видимым, доступным всем единицами трансляции. Это значит, что вы должны определить такой символ в конкретном месте одной единицы трансляции, обычно в файле реализации (.c/.cpp), так чтобы у него было только одно видимое определение. Если вы попытаетесь одновременно с объявлением символа выполнить его определение, или поместить определение в файл к объявлению, то рискуете разозлить компоновщик. Попытка добавить файл больше чем в один файл реализации, ведет к добавлению определения больше чем в одну единицу трансляции — ваш компоновщик будет плакать.
Ключевое слово extern в C и C++ (явно) объявляет, что у символа есть внешняя связь.
Оба символа имеют внешнюю связь. Выше отмечалось, что const глобальные переменные по умолчанию имеют внутреннее связывание, non-const глобальные переменные — внешнее. Это значит, что int x; — то же самое, что и extern int x;, верно? Не совсем. int x; на самом деле аналогичен extern int x<>; (используя синтаксис универсальной/скобочной инициализации, для избежания самого неприятного синтаксического анализа (the most vexing parse)), так как int x; не только объявляет, но и определяет x. Следовательно, не добавить extern к int x; глобально настолько же плохо, как определить переменную при объявлении ее extern:
Давайте объявим функцию f с внешней связью в file.hpp и там же определим ее:
Обратите внимание, что добавлять здесь extern не нужно, так как все функции явно extern. Разделения объявления и определения тоже не потребуется. Поэтому давайте просто перепишем это следующим образом:
Такой код можно было бы написать до прочтения этой статьи, либо после ее чтения под воздействием алкоголя или тяжелых веществ (например, булочек с корицей).
Давайте посмотрим, почему так делать не стоит. Теперь у нас есть два файла реализации: a.cpp и b.cpp, оба включены в file.hpp:
Теперь пусть поработает компилятор и сгенерирует две единицы трансляции для двух файлов реализации выше (помните что #include буквально означает копировать/вставить):
На этом этапе вмешивается компоновщик (связывание происходит после компиляции). Компоновщик берет символ f и ищет определение. Сегодня ему повезло, он находит аж два! Одно в единице трансляции A, другое в B. Компоновщик замирает от счастья и говорит вам примерно следующее:
Стандартным примером объявления переменных extern являются глобальные переменные. Предположим, вы работаете над самовыпекаемым тортом. Наверняка есть глобальные переменные, связанные с тортом, которые должны быть доступны в разных частях вашей программы. Допустим, тактовая частота съедобной схемы внутри вашего торта. Это значение естественно требуется в разных частях для синхронной работы всей шоколадной электроники. (Злой) C-способ объявления такой глобальной переменной имеет вид макроса:
Программист C++, испытывающий к макросам отвращение, лучше напишет настоящий код. Например такой:
(Современный программист C++ захочет использовать разделительные литералы: unsigned int clock_rate = 1’000’000;)
Если у символа есть внутренняя связь, то он будет виден только внутри текущей единицы трансляции. Не путайте видимость с правами доступа, например private. Видимость означает, что компоновщик сможет использовать этот символ только при обработке единицы трансляции, в которой был объявлен символ, а не позже (как в случае символов с внешней связью). На практике, это значит, что при объявлении символа с внутренней связью в заголовочном файле, каждая единица трансляции, включающая в себя этот файл, получит уникальную копию этого символа. Как если бы вы предопределили каждый такой символ в каждой единице трансляции. Для объектов это значит, что компилятор будет буквально выделять совершенно новую, уникальную копию для каждой единицы трансляции, что, очевидно, может привести к высоким расходам памяти.
Для объявления символа с внутренней связью, в C и C++ существует ключевое слово static. Такое использование отличается от применения static в классах и функциях (или, в целом, в любых блоках).
Каждая единица трансляции, включающая header.hpp получает уникальную копию переменной, в силу наличия у нее внутренней связи. Есть три единицы трансляции:
Анонимные пространства имен
В С++ существует другой способ объявления одного и более символов с внутренней связью: анонимные пространства имен. Такое пространство гарантирует, что символы, объявленные внутри него, видны только в текущей единице трансляции. По сути, это просто способ объявить несколько символов static. Какое-то время от использования ключевого слова static в целях объявления символа с внутренней связью отказались в пользу анонимных пространств имен. Однако, им снова стали пользоваться в силу удобства объявления одной переменной или функции с внутренней связью. Есть еще несколько незначительных отличий, на которых я не буду останавливаться.
В любом случае, это:
Делает (почти) то же самое, что и:
Так в каких же случаях пользоваться внутренними связями? Использовать их для объектов — плохая идея. Расход памяти больших объектов может быть очень высок из-за копирования под каждую единицу трансляции. Но, в основном, это просто вызывает странное, непредсказуемое поведение. Представьте, что у вас есть синглтон (класс, в котором вы создаете экземпляр только одного инстанса) и неожиданно появляется несколько инстансов вашего “синглтона” (по одному на каждую единицу трансляции).
Однако, внутреннюю связь можно использовать для скрытия из глобальной области локальных хелпер-функций единицы трансляции. Допустим, есть хелпер-функция foo в file1.hpp, которую вы используете в file1.cpp. В то же время у вас есть функция foo в file2.hpp, используемая в file2.cpp. Первая и вторая foo отличаются друг от друга, но вы не можете придумать другие имена. Поэтому вы можете объявить их static. Если вы не будете добавлять и file1.hpp, и file2.hpp в одну и ту же единицу трансляции, то это скроет foo друг от друга. Если этого не сделать, то они будут неявно иметь внешнюю связь и определение первой foo столкнется с определением второй, вызвав ошибку компоновщика о нарушении правила одного определения.
Вы всегда можете оставить свои комментарии и\или вопросы тут или зайти к нам на день открытых дверей.
не линкуется
upd. 03-07. Программа линкуется, если полностью закомментировать описание функций operator Свернуть исходник
#ifndef INC_IOS
#define INC_IOS
#include
#endif
using namespace std ;
#ifndef INC_IOS
#define INC_IOS
#include
#endif
MyDate :: MyDate ( )
<
m_day = 1 ;
m_month = 1 ;
m_year = 1 ;
>
MyDate :: MyDate ( int newDay, int newMonth, int newYear )
<
m_year = 1 ;
m_month = 1 ;
m_day = 1 ;
if ( SetYear ( newYear ) )
m_year = 1 ;
if ( SetMonth ( newMonth ) )
m_month = 1 ;
if ( SetDay ( newDay ) )
m_day = 1 ;
>
int MyDate :: GetYear ( ) const
<
return m_year ;
>
int MyDate :: GetMonth ( ) const
<
return m_month ;
>
int MyDate :: GetDay ( ) const
<
return m_day ;
>
bool MyDate :: KeybInput ( )
<
int error, buff ;
do
<
cout «Enter year: » ;
cin >> buff ;
error = SetYear ( buff ) ;
switch ( error )
<
case 0 :
cout «OK» ;
break ;
case 1 :
cout «Can’t be zero!» endl ;
//break;
return true ;
case 2 :
cout «It’s february 29th and year can’t be accepted!» ;
break ;
>
cout endl ;
> while ( error ) ;
do
<
cout «Enter month: » ;
cin >> buff ;
error = SetMonth ( buff ) ;
switch ( error )
<
case 0 :
cout «OK» ;
break ;
case 1 :
cout «Too small!» ;
break ;
case 2 :
cout «Too big!» ;
break ;
case 3 :
cout «Cannot be with curent day!» ;
break ;
>
cout endl ;
> while ( error ) ;
do
<
cout «Enter day: » ;
cin >> buff ;
error = SetDay ( buff ) ;
switch ( error )
<
case 0 :
cout «OK» ;
break ;
case 1 :
cout «Too small!» ;
break ;
case 2 :
cout «Too big!» ;
break ;
case 3 :
cout «Re-check leap year!» ;
break ;
>
cout endl ;
> while ( error ) ;
return false ;
>
if ( m_day > 30 )
<
m_month ++ ;
m_day = 1 ;
return ;
>
if ( m_day > 29 )
switch ( m_month )
<
case 4 :
case 6 :
case 9 :
case 11 :
m_month ++ ;
m_day = 1 ;
return ;
>
#ifndef INC_IOS
#define INC_IOS
#include
#endif
using namespace std ;
class MyDate
<
unsigned char m_day ;
unsigned char m_month ;
int m_year ;
public :
MyDate ( int newDay, int newMonth, int newYear ) ;
MyDate ( ) ;
int SetDay ( int newDay ) ;
int SetMonth ( int newMonth ) ;
int SetYear ( int newYear ) ;
int GetDay ( ) const ;
int GetMonth ( ) const ;
int GetYear ( ) const ;