Почему необходимо связать математическую библиотеку в C?

Если мы посмотрим на исходный код, то увидим, что AsyncTask и Handler написаны исключительно на Java. (Однако есть некоторые исключения. Но это не важный момент).

Так что в AsyncTask или Handler нет магии. Эти классы облегчают нашу жизнь как разработчика.

Например: если программа A вызывает метод A (), метод A () может выполняться в другом потоке с программой A. Мы можем легко проверить с помощью следующего кода:

Thread t = Thread.currentThread();    
int id = t.getId();

Почему мы должны использовать новый поток для некоторых задач? Вы можете Google для этого. Много много причин, например: тяжелые подъемы, длительные работы.

Итак, каковы различия между Thread, AsyncTask и Handler?

AsyncTask и Handler написаны на Java (внутренне они используют Thread), так что все, что мы можем сделать с Handler или AsyncTask, мы можем достичь с помощью Thread.

Чем действительно могут помочь Handler и AsyncTask?

Наиболее очевидной причиной является связь между потоком вызывающего и рабочим потоком. ( Поток вызывающих : Поток, который вызывает рабочий поток для выполнения некоторых задач. Поток вызывающих не обязательно должен быть потоком пользовательского интерфейса). Конечно, мы можем общаться между двумя потоками другими способами, но есть много недостатков (и опасностей) из-за безопасности потоков.

Вот почему мы должны использовать Handler и AsyncTask. Эти классы выполняют большую часть работы за нас, нам нужно только знать, какие методы переопределить.

Разница между Handler и AsyncTask заключается в следующем: Используйте AsyncTask, когда Поток вызывающего абонента является Поток пользовательского интерфейса . Вот что говорится в документе Android:

AsyncTask позволяет правильно и легко использовать поток пользовательского интерфейса. Этот класс позволяет выполнять фоновые операции и публиковать результаты в потоке пользовательского интерфейса без необходимости манипулировать потоками и / или обработчиками.

Я хочу подчеркнуть два момента:

1) Простое использование поток пользовательского интерфейса (поэтому используйте, когда потоком вызывающего является поток пользовательского интерфейса).

2) Нет необходимости манипулировать обработчиками. (означает: вы можете использовать Handler вместо AsyncTask, но AsyncTask - более простой вариант).

В этом посте есть много вещей, которые я еще не сказал, например: что такое поток пользовательского интерфейса или почему это проще. Вы должны знать некоторые методы каждого класса и использовать его, вы полностью поймете причину.

@: когда вы читаете документ Android, вы увидите:

Обработчик позволяет отправлять и обрабатывать объекты Message и Runnable, связанные с MessageQueue потока

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

Сложно? Просто помните, что Handler может безопасно общаться с потоком вызывающего.

239
задан Chris 7 October 2012 в 21:45
поделиться

9 ответов

Функции в stdlib.h и stdio.h имеют реализации в libc.so (или libc .a для статического связывания), который по умолчанию связан с вашим исполняемым файлом (как если бы были указаны -lc ). GCC может быть проинструктирован избегать этой автоматической связи с параметрами -nostdlib или -nodefaultlibs .

Математические функции в math.h имеют реализации в libm.so (или libm.a для статической компоновки) и libm по умолчанию не связаны. У этого разделения libm / libc есть исторические причины, но ни одна из них не очень убедительна.

Интересно, что среда выполнения C ++ libstdc ++ требует libm ,

231
ответ дан 23 November 2019 в 03:21
поделиться

Помните, что C - старый язык, а FPU - относительно недавнее явление. Я впервые увидел C на 8-битных процессорах, где даже 32-битная целочисленная арифметика требовала много работы. Многие из этих реализаций даже не имели доступной математической библиотеки с плавающей запятой!

Даже на первых 68000 машинах (Mac, Atari ST, Amiga) сопроцессоры с плавающей запятой часто были дорогостоящими надстройками.

Чтобы выполнять всю эту математику с плавающей запятой, вам нужна была довольно большая библиотека. И математика будет медленной. Значит, вы редко использовали поплавки. Вы пытались делать все с целыми или масштабированными целыми числами. Когда вам пришлось включить math.h, вы стиснули зубы. Часто, чтобы избежать этого, вы должны писать свои собственные аппроксимации и справочные таблицы.

Компромиссы существовали долгое время. Иногда существовали конкурирующие математические пакеты, называемые «fastmath» или подобные. Какое лучшее решение для математики? Действительно точный, но медленный материал? Неточно, но быстро? Большие таблицы для триггерных функций? Большинство реализаций стало очевидным только после того, как в компьютере было гарантировано наличие сопроцессоров. Я полагаю, что сейчас где-то там есть программист, который работает над встроенным чипом и пытается решить, использовать ли математическую библиотеку для решения какой-нибудь математической задачи.

Вот почему математика не была стандартом . Многие или, может быть, большинство программ не использовали ни одного числа с плавающей запятой. Если бы FPU всегда были рядом, а поплавки и двойники всегда были дешевы в эксплуатации, без сомнения, существовала бы "стандартная математика"

.
73
ответ дан 23 November 2019 в 03:21
поделиться

Как сказано в ephemient, библиотека C libc связана по умолчанию, и эта библиотека содержит реализации stdlib.h, stdio.h и несколько других стандартных файлов заголовков. Чтобы добавить к этому, согласно « Введение в GCC » команда компоновщика для базовой программы «Hello World» на C выглядит следующим образом:

ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o 
/usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc 
-lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o

Обратите внимание на параметр -lc в третьей строке, которая связывает библиотеку C.

5
ответ дан 23 November 2019 в 03:21
поделиться

Объяснение приводится здесь :

Итак, если ваша программа использует математические функции и включает math.h , тогда вам нужно явно связать математическую библиотеку, передав флаг -lm . Причина этого особого разделения заключается в том, что математики очень разборчивы в том, как вычисляется их математика, и они могут захотеть использовать свою собственную реализацию математических функций вместо стандартной реализации. Если бы математические функции были объединены в libc.a , это было бы невозможно.

[Edit]

Я не уверен, что согласен с этим. Если у вас есть библиотека, которая предоставляет, скажем, sqrt () , и вы передаете ее перед стандартной библиотекой, компоновщик Unix возьмет вашу версию, верно?

26
ответ дан 23 November 2019 в 03:21
поделиться

Подробное обсуждение связывания с внешними библиотеками содержится в Введение в GCC - Связывание с внешними библиотеками . Если библиотека является членом стандартных библиотек (например, stdio), вам не нужно указывать компилятору (на самом деле компоновщику) для их связывания.

РЕДАКТИРОВАТЬ: После прочтения некоторых других ответов и комментариев, Я думаю, что ссылка libc.a и ссылка libm, на которые она ссылается, могут многое сказать о том, почему они разделены.

Обратите внимание, что многие функции в 'libm.a' ( математическая библиотека) определены в 'math.h', но отсутствуют в libc.a. Некоторые из них могут сбивать с толку, но практическое правило таково - библиотека C содержит те функции, которые, по мнению ANSI, должны существовать, поэтому вы не должны -lm нужен, если вы используете только функции ANSI. Напротив, libm.a содержит больше функций и поддерживает дополнительные функции, такие как обратный вызов matherr и соответствие нескольким альтернативным стандартам поведения в случае ошибок FP. Смотрите раздел libm, для более подробной информации.

4
ответ дан 23 November 2019 в 03:21
поделиться

stdio является частью стандартной библиотеки C, с которой по умолчанию связывается gcc.

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

2
ответ дан 23 November 2019 в 03:21
поделиться

Если я помещаю stdlib.h или stdio.h, мне не нужно связывать их, но я должен ссылаться при компиляции:

stdlib.h , stdio.h - файлы заголовков. Вы включаете их для вашего удобства. Они только прогнозируют, какие символы станут доступны, если вы сделаете ссылку в соответствующей библиотеке. Реализации находятся в файлах библиотеки, где на самом деле живут функции.

Включение math.h - это только первый шаг к получению доступа ко всем математическим функциям.

Кроме того, вы этого не сделаете. Если вы не используете его функции, необходимо ссылаться на libm , даже если вы выполняете #include , который является лишь информационным шагом для вас, для компилятор о символах.

stdlib.h , stdio.h относятся к функциям, доступным в libc ,

3
ответ дан 23 November 2019 в 03:21
поделиться

Я бы предположил , что это способ сделать приложения, которые его вообще не используют, немного лучше. Вот мои мысли по этому поводу.

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

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

Итак, если вы вообще не связываете какой-либо математический код, ничего из этого не произойдет, поэтому ОС вообще не нужно сохранять / восстанавливать какое-либо состояние FPU, делает переключение контекста немного более эффективным.

Просто предположение.

РЕДАКТИРОВАТЬ: в ответ на некоторые из комментариев,

2
ответ дан 23 November 2019 в 03:21
поделиться

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

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

РЕДАКТИРОВАТЬ: (из моих собственных комментариев): Я думаю, что gcc делает это, чтобы поддерживать обратную совместимость с исходным cc. Я предполагаю, почему cc делает это из-за времени сборки - cc был написан для машин с гораздо меньшей мощностью, чем у нас сейчас. Во многих программах нет математики с плавающей запятой, и они, вероятно, взяли все библиотеки, которые обычно не использовались, по умолчанию. Я предполагаю, что время сборки ОС UNIX и инструментов, которые идут вместе с ней, были движущей силой.

3
ответ дан 23 November 2019 в 03:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: