LINUX.ORG.RU

Как ардуино/AVR оперирует int 16-bit, long 32-bit и float 32-bit? Всё чисто программное?

 , , , ,


1

2

https://learn.sparkfun.com/tutorials/data-types-in-arduino

Хотелось бы узнать у любителей AVR ASM'а как на самом низком уровне оперирует числами: у него реализован специальный аппаратный модуль для работы с int 16-bit, он программно эмулируется = тормзит?

float, я так понимаю, там только программный, верно?


Ответ на: комментарий от beastie

Какая разница как организован доступ к памяти? В конечном счёте все операции производятся с использованием подгруженными из памяти данными в L1-кэше и регистрах оконечных вычислительных устройств в момент самой операции... Хотя, блин, в этом говне, кажись, это не так. Конченое арифметическое устройство то в какой битности максимальной работает?

mklord
() автор топика

И да, совсем не обязательно, что программная математика будет тормозить. Например, 32-битное сложение на 16-битном x86 будет занимать всего лишь 2 команды вместо 1-ой.

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

И да, совсем не обязательно, что программная математика будет тормозить. Например, 32-битное сложение на 16-битном x86 будет занимать всего лишь 2 команды вместо 1-ой.

Что это у Вас за сложение такое? В котором переполнение малого регистра никогда не происходит? Обычно это 3-4 операции МИНИМУМ: выполнение сложения малых регистров, проверка флага переполнения (это если ещё есть, а то под него придётся старший бит младшего регистра юзать и число станет 15-битным), если переполнилось, то прибавляем 1 к старшему регистру и производим сложение старших регистров, если нет просто складываем старшие регистры.

С делением без аппаратной реализации будет вообще жопа тактов на 20.

Если МК не ногой дрыгает пару раз в секунду, а программно генерит ШИМ или PCM, то это может стать проблемой.

mklord
() автор топика
Ответ на: комментарий от KivApple

Даташит на какую-нибудь ATMEGA328 скачать не вариант?

Я не настолько хорошо в архитектуре МК разбираюсь, да и лень. :3

mklord
() автор топика
Ответ на: комментарий от mklord

Что это у Вас за сложение такое?

Да как у нормальных людей - add|adc с учетом бита переноса. 2 команды, как и сказали выше. Аппаратного деления в серии Tiny например вообще нет. Но вам с такими запросами проще заюзать комп с математическим сопроцессором и не натягивать сову на глобус.

Ivana
()
Ответ на: комментарий от mklord
add ax, cx
adc dx, bx

Это код сложения 32-битного числа числа AX:DX и CX:BX (результат окажется в AX:DX) для процессора x86. Сколько тут команд? У всех остальных нормальных архитектур (в том числе RISC) есть аналогичные команды. RISC оно вообще только в том проявляется, что надо данные грузить в регистры прежде чем с ними что-то можно сделать. А набор команд работы с регистрами может быть весьма обширным (у ARM, например, вообще есть такие команды, о которых пользователи x86 могут только мечтать).

С вычитанием аналогичная ситуация. С умножением и делением чуть сложнее, но тоже не так уж и плохо. Если есть аппаратный умножитель/делитель. А, например, последнего у AVR нет (даже для 8 бит). Программная же реализация обычно линейно зависит от разрядности (в 2 раза больше разрядность - в 2 раза больше действий).

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

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

mklord
() автор топика
Ответ на: комментарий от mklord

Таким образом можно складывать числа произвольной разрядности, хоть 256-битные. При этом зависимость количества инструкций от разрядности будет линейная (разве что не хватит регистров, чтобы загрузить всё число и придётся делать подгрузку-сохранение на промежуточных этапах). Этот код работал бы даже на самых первых x86, которые появились когда 32-битности ещё и в проекте не было. Как и микрокода.

Всё просто. Команда сложения add в случае переполнения взводит специальный флаг (по сути дела просто сложение выполняется не 16-битное, а 17-битное, но старший бит уходит во флаг). А команда сложения adc делает то же самое, но прибавляет к результату старое значение флага (если было переполнение, то результат будет на единицу больше, если не было, то таким же как и после обычного сложения). Аналогичные команды есть практически на любой архитектуре, включая многие RISC. И AVR не исключение.

«Всё гениальное - просто» (с)

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 4)
Ответ на: комментарий от mklord

Сказано же тебе - сумматор просто на 1 бит больше, чем надо. И лишний бит после операции уходит в регистр флагов. И есть специальная инструкция, которая складывает сразу 3 числа - аргументы, которые указал программист и однобитный регистр флагов. Такой набор инструкций - стандарт де факто для всех архитектур. И да, если открыть в даташите страницу про набор инструкций, то там прямо первыми в списке идут ADD и ADC, которые делают ровно то же самое, что и соответствующие инструкции на x86, только размеры операндов у них 8 бит, а не 16 (а значит для сложения 32-битных чисел потребуется 4 инструкции вместо 2, а для сложения 16-битных 2 вместо одной). Аналогичная ситуация для функций вычитания - точно также как на x86, на AVR есть команды вычитания, которые учитывают результат прошлой операции (если мы вычитаем из меньшего большего взводится специальный флаг).

Кстати, если прокрутить список инструкций дальше, можно увидеть, что команда умножения принимает значения из одиночных регистров, а пишет результат в пару регистров. То есть умножение 8-битных чисел всегда даёт 16-битное число. На x86 абсолютно такая же ситуация - результат умножения всегда в 2 раза шире аргументов (а делимое всегда в 2 раза шире делителя и частного, но на AVR нет аппаратного деления). И тут всё получается опять же банально. Бежим по байтикам числа и умножаем их по отдельности и складываем каждый со старшим байтом результата умножения предыдущего (разумеется, складываем с помощью ADC).

Только вот если ты такой умный, что споришь со мною, а не веришь мне на слово - почему ты сам не загуглил?

Кстати, угадай сколько команд занимает установка/снятие бита в числе?

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 3)
Ответ на: комментарий от mklord

Что это у Вас за сложение такое? В котором переполнение малого регистра никогда не происходит? Обычно это 3-4 операции МИНИМУМ

Идиот.

man ADD man ADC

anonymous
()
Ответ на: комментарий от intelfx

http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_ADC.html Спс. Сразу бы кинули ссылку на правильный запрос в гугл. Короче там полупрограммая реализация: первая команда складывает младший регистр, вторая складывает старшие плюс прибавляет бит переполнения младшего. Обе команды разные.

mklord
() автор топика
Ответ на: комментарий от anonymous

Идиот.

Идиот — в Древней Греции человек, живущий в отрыве от общественной жизни, не участвующий в общем собрании граждан полиса и иных формах государственного и общественного демократического управления. Причём тут моё неучастие в жизни форума?

man ADD man ADC

Уже загуглил.

mklord
() автор топика
Ответ на: комментарий от KivApple

Ну про умножение ещё можно понять (хотя не всегда там реально будет нужно два регистра), но вот

а делимое всегда в 2 раза шире делителя и частного, но на AVR нет аппаратного деления

уже форменный бред: 11111111 11111111/10= 01111111 11111111

Ок, а что с командами аппаратного умножения и деления на AVR? Если там нет аппаратного деления, то сколько тактов стоит эмуляция?

И почему у x86 нет команд для прямой работы с 32-битными и 64-битными числами? Это весьма логично даже тупо с точки зрения экономии памяти в кэшах и конвеере: банально даже через микрокод можно реализовать.

Кстати, угадай сколько команд занимает установка/снятие бита в числе?

Одна же. Делается через сложение. Или ты о каком-то «сервисном» бите состояния?

mklord
() автор топика
Ответ на: комментарий от mklord

Да нет, не бред. И в данном случае старший байт будет утерян. Таким образом делить можно только так, чтобы результат влез. Однако очень часто программист делает uint32 = uint64 / uint32 и уверен, что результат будет корректен. Поэтому инструкция весьма полезна.

В x86 есть команды прямой работы с 32-битным числами начиная с i386 и с 64-битными начиная с поддержки 64-битной адресации. При этом 64-битные инструкции доступны только в специальном режиме, а 32-битные инструкции доступны и в 16-битном режиме.

Однако все эти правила применяются и к ним же. ADC существует и в 32/64 битных версиях. 32-битное умножение выдаёт 64-битный результат в паре 32-битных регистров. 64-битное умножение выдаёт 128-битный результат в паре 64-битных регистров.

В AVR есть только 8-битные инструкции, однако правила те же (есть ADC, а умножение выдаёт 16 бит).

Ах да, ответ про возведение бита не верен. А что если этот бит уже стоял? Тогда получится чушь. Сложение используют только быдлокодеры. Нормальные люди используют OR (а для снятия бита AND). Однако что если у тебя известен лишь номер бита, а не сам бит (типа установить i-ый бит числа)?

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

Однако очень часто программист делает uint32 = uint64 / uint32 и уверен, что результат будет корректен. Поэтому инструкция весьма полезна.

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

При этом 64-битные инструкции доступны только в специальном режиме

А как же какая-то байда в линуксе (что-то там ABI), которая позволяет использовать 32-bit-адресуемым приложениям 64-bit-команды?

64-битное умножение выдаёт 128-битный результат в паре 64-битных регистров.

Лол, это уже может быть крайне неудобно.

mklord
() автор топика
Ответ на: комментарий от mklord

Лол, это уже может быть крайне неудобно.

Тупо игноришь второй регистр результата, если он тебе не нужен. При желании можешь проверить его на ноль, если боишься переполнения. Если не боишься, можешь не проверять. Ни одной лишней команды, зато получаешь очень быструю длинную арифметику. В чём проблема?

Это весьма стреляние в ногу.

Открою тебе секрет - в Си как правило никак не проверяется переполнение ни при сложении, ни при умножении, ни при делении. Единственное исключение, которое может возникнуть - деление на ноль. Так что никакой угрозы безопасности - программисту в любом случае придётся думать головой. Зато ускорение популярной операции.

А как же какая-то байда в линуксе (что-то там ABI), которая позволяет использовать 32-bit-адресуемым приложениям 64-bit-команды?

Ничего такого мне неизвестно. Я лишь знаю, что 64-битное ядро можешь запускать 32-битные приложения. Однако при этом им будет недоступно не только больше 4 ГБ памяти (впрочем, у каждого приложения это могут быть разные 4 ГБ, так что в сумме они смогут сожрать больше), но и 64-битные инструкции.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

Открою тебе секрет

Я знаю, я факт констатирую. Факт ненужности сей и офигенности явы.

Ничего такого мне неизвестно. Я лишь знаю, что 64-битное ядро можешь запускать 32-битные приложения. Однако при этом им будет недоступно не только больше 4 ГБ памяти (впрочем, у каждого приложения это могут быть разные 4 ГБ, так что в сумме они смогут сожрать больше), но и 64-битные инструкции.

https://ru.wikipedia.org/wiki/X32_ABI Очевидно, что костыль, но не совсем понятно, как работает.

mklord
() автор топика

Идиот.

Разделяю точку зрения. Спрашивать «как это все реализовано конкретно в АВР» после того как 5 человек написали прямые команды... И не понимать азов ассемблера, как установить/снять/инвертировать бит, даже как складывать... И при этом с таким гонором кидать претензии не по делу...

Ivana
()
Ответ на: комментарий от Ivana

И не понимать азов ассемблера

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

mklord
() автор топика
Ответ на: комментарий от mklord

Факт ненужности сей и офигенности явы.

С другой стороны, это позволяет работать быстрее за счёт отсутствия проверок там, где программист уверен, что результат влезет. И уж и тем более это критично для прошивки для AVR. Ибо удваивать количество инструкций (условный переход на код обработки переполнения) ради того, чтобы программист чуть меньше думал (хотя нет, думать всё равно придётся, ибо если прошивка упадёт это будет ничуть не лучше переполнения) - непозволительная роскошь. А ещё иногда переполнение можно использовать в свою пользу.

Насчёт X32 ABI не совсем понятно о чём идёт речь. Из статьи на википедии совершенно не ясно, что программы могут использовать 64-битные операции. Там наоборот говорится про «32-битные указатели и поля данных».

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

хотя нет, думать всё равно придётся, ибо если прошивка упадёт это будет ничуть не лучше переполнения

Вообще-то лучше: лучше пусть упадёт и встанет колом (или аварийно отключится/ребутнётся), чем угробит станок за несколько лямов, который к контроллеру подключен. Или лифт пробъёт днище шахты.

А ещё иногда переполнение можно использовать в свою пользу.

Это когда? Когда систему ломаешь и эксплойты пишешь? :)

Там наоборот говорится про «32-битные указатели и поля данных».

Ииииииииииии?

mklord
() автор топика
Ответ на: комментарий от mklord

Это когда? Когда систему ломаешь и эксплойты пишешь? :)

Да нет. Ну например, есть у меня кольцевой буфер на 256 байт. Беру и объявляю все смещения в нём как uint8_t. И код сразу упрощается. Не надо писать index = (index + 1) % 256. Всё случится само.

Это первый пример, что пришёл в голову. На самом деле бывает немало случаев, когда можно элегантно использовать переполнение целочисленной переменной.

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

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Квадратично же! Разрядность выше в 2 раза - действий больше в 4 раза.

anonymous
()
Ответ на: комментарий от mklord

Это когда делаешь синтезаторы частоты, кольцевые буфера и все такое.

anonymous
()
Ответ на: комментарий от mklord

Если ребутнется контроллер станка или частотник в насосе во время работы, последствия могут быть ОЧЕ серьезными, в т.ч. гибель людей. Поэтому программа не должна падать, вообще не должна!

anonymous
()

конечно программно

Harald ★★★★★
()
Ответ на: комментарий от anonymous

Поэтому программа не должна падать, вообще не должна!

Тогда почему до сих пор нет явы под контроллеры?!

mklord
() автор топика
Ответ на: комментарий от mklord

да так, один забаненный любитель покупать чужие аккаунты

Harald ★★★★★
()
Ответ на: комментарий от mklord

Мне претит мутная личность с неясными целями и видимым недостатком умения себя занять. Ещё и подозрительно настойчивая.

иллитарное

Позёрское.

contra_sperm_spero
()

Программно. Про float-сопроцессоры для восьмибиток не слышал.

Причем для контроллеров программа должна быть как можно меньше; еще пару лет назад были голоса «нафиг ваш C, я на ассемблере все компактнее оформлю!». Память программ для всяких ATTiny ограничена сотнями байт. Полкилобайта на программу и стек — это очень негусто.

Складывать умеем только 8-битные регистры; в 64-битном числе 8 таких частей. Нужно и их просуммировать, и промежуточные переносы учитывать. А чтобы просто загрузить число в память, нужны 8 операций. И еще 8, чтобы выгрузить.

В итоге удлиненная арифметки будет очень емким.

Поставь avr-gcc, и скомпилируй такую прогу:

#include <stdint-gcc.h>


int8_t add8(int8_t num) {
	num += 10;
	return num;
}

int32_t add32(int32_t num) {
	num += 10;
	return num;
}

float addfloat(float num) {
	num += 10;
	return num;
}

int64_t add64(int64_t num) {
	num += 10;
	return num;
}

int main() {

	int8_t i8 = 100;
	int32_t i32 = 101;
	int64_t i64 = 102;
	float f = 103;

	i8 = add8(i8);
	i32 = add32(i32);
	i64 = add64(i64);
	f = addfloat(f);
	return 0;
}

чтобы увидеть ассемблерный код в файле main.s, скомандуй

avr-gcc -S main.c

add_64 кажется компактным?

add64:
	push r10
	push r11
	push r12
	push r13
	push r14
	push r15
	push r16
	push r17
	push r28
	push r29
	in r28,__SP_L__
	in r29,__SP_H__
	sbiw r28,8
	in __tmp_reg__,__SREG__
	cli
	out __SP_H__,r29
	out __SREG__,__tmp_reg__
	out __SP_L__,r28
/* prologue: function */
/* frame size = 8 */
/* stack size = 18 */
.L__stack_usage = 18
	std Y+1,r18
	std Y+2,r19
	std Y+3,r20
	std Y+4,r21
	std Y+5,r22
	std Y+6,r23
	std Y+7,r24
	std Y+8,r25
	ldd r18,Y+1
	ldd r19,Y+2
	ldd r20,Y+3
	ldd r21,Y+4
	ldd r22,Y+5
	ldd r23,Y+6
	ldd r24,Y+7
	ldd r25,Y+8
	ldi r26,lo8(10)
	rcall __adddi3_s8
	mov r10,r18
	mov r11,r19
	mov r12,r20
	mov r13,r21
	mov r14,r22
	mov r15,r23
	mov r16,r24
	mov r17,r25
	std Y+1,r10
	std Y+2,r11
	std Y+3,r12
	std Y+4,r13
	std Y+5,r14
	std Y+6,r15
	std Y+7,r16
	std Y+8,r17
	ldd r18,Y+1
	ldd r19,Y+2
	ldd r20,Y+3
	ldd r21,Y+4
	ldd r22,Y+5
	ldd r23,Y+6
	ldd r24,Y+7
	ldd r25,Y+8
	mov r10,r18
	mov r11,r19
	mov r12,r20
	mov r13,r21
	mov r14,r22
	mov r15,r23
	mov r16,r24
	mov r17,r25
	mov r18,r10
	mov r19,r11
	mov r20,r12
	mov r21,r13
	mov r22,r14
	mov r23,r15
	mov r24,r16
	mov r25,r17
/* epilogue start */
	adiw r28,8
	in __tmp_reg__,__SREG__
	cli
	out __SP_H__,r29
	out __SREG__,__tmp_reg__
	out __SP_L__,r28
	pop r29
	pop r28
	pop r17
	pop r16
	pop r15
	pop r14
	pop r13
	pop r12
	pop r11
	pop r10
	ret
	.size	add64, .-add64
anonymous
()
Ответ на: комментарий от anonymous

А вот это мейн:

main:
	push r10
	push r11
	push r12
	push r13
	push r14
	push r15
	push r16
	push r17
	push r28
	push r29
	in r28,__SP_L__
	in r29,__SP_H__
	sbiw r28,17
	in __tmp_reg__,__SREG__
	cli
	out __SP_H__,r29
	out __SREG__,__tmp_reg__
	out __SP_L__,r28
/* prologue: function */
/* frame size = 17 */
/* stack size = 27 */
.L__stack_usage = 27
	ldi r24,lo8(100)
	std Y+1,r24
	ldi r24,lo8(101)
	ldi r25,0
	ldi r26,0
	ldi r27,0
	std Y+2,r24
	std Y+3,r25
	std Y+4,r26
	std Y+5,r27
	ldi r24,lo8(102)
	std Y+6,r24
	std Y+7,__zero_reg__
	std Y+8,__zero_reg__
	std Y+9,__zero_reg__
	std Y+10,__zero_reg__
	std Y+11,__zero_reg__
	std Y+12,__zero_reg__
	std Y+13,__zero_reg__
	ldi r24,0
	ldi r25,0
	ldi r26,lo8(-50)
	ldi r27,lo8(66)
	std Y+14,r24
	std Y+15,r25
	std Y+16,r26
	std Y+17,r27
	ldd r24,Y+1
	rcall add8
	std Y+1,r24
	ldd r24,Y+2
	ldd r25,Y+3
	ldd r26,Y+4
	ldd r27,Y+5
	mov r22,r24
	mov r23,r25
	mov r24,r26
	mov r25,r27
	rcall add32
	mov r27,r25
	mov r26,r24
	mov r25,r23
	mov r24,r22
	std Y+2,r24
	std Y+3,r25
	std Y+4,r26
	std Y+5,r27
	ldd r10,Y+6
	ldd r11,Y+7
	ldd r12,Y+8
	ldd r13,Y+9
	ldd r14,Y+10
	ldd r15,Y+11
	ldd r16,Y+12
	ldd r17,Y+13
	mov r18,r10
	mov r19,r11
	mov r20,r12
	mov r21,r13
	mov r22,r14
	mov r23,r15
	mov r24,r16
	mov r25,r17
	rcall add64
	mov r10,r18
	mov r11,r19
	mov r12,r20
	mov r13,r21
	mov r14,r22
	mov r15,r23
	mov r16,r24
	mov r17,r25
	std Y+6,r10
	std Y+7,r11
	std Y+8,r12
	std Y+9,r13
	std Y+10,r14
	std Y+11,r15
	std Y+12,r16
	std Y+13,r17
	ldd r24,Y+14
	ldd r25,Y+15
	ldd r26,Y+16
	ldd r27,Y+17
	mov r22,r24
	mov r23,r25
	mov r24,r26
	mov r25,r27
	rcall addfloat
	mov r27,r25
	mov r26,r24
	mov r25,r23
	mov r24,r22
	std Y+14,r24
	std Y+15,r25
	std Y+16,r26
	std Y+17,r27
	ldi r24,0
	ldi r25,0
/* epilogue start */
	adiw r28,17
	in __tmp_reg__,__SREG__
	cli
	out __SP_H__,r29
	out __SREG__,__tmp_reg__
	out __SP_L__,r28
	pop r29
	pop r28
	pop r17
	pop r16
	pop r15
	pop r14
	pop r13
	pop r12
	pop r11
	pop r10
	ret
	.size	main, .-main
	.ident	"GCC: (GNU) 4.8.2"

Разворачивание кода — колоссальное. Если длинно-вычислительного кода много, то и килобайта может не хватить, так что в мелкие контроллеры советую совсем не залезать. 16 КБ хватит всем, в вот меньше — нафиг надо.

anonymous
()
Ответ на: комментарий от mklord

Потому что она тормозит и жрёт память, а её на контроллерах мало.

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

А ещё контроллерам часто нужна риалтаймовость. То есть чтобы можно было предсказать время исполнения некоторых участков кода с точностью до такта или около того. В случае сишечки можно подсмотреть ассемблерных листинг. Или даже сделать ассемблерную вставку. В случае жабы нет никаких гарантий скорости выполнения кода, ибо либо он генерируется JIT и вообще рандомный, либо работает медленная интерпретация. А ещё внезапно может запуститься сборщик мусора и вся система встанет колом.

Да, с миганием светодиодом на жабе проблем не будет. Но когда речь зайдёт о каких-то вещах типа всяких синтезаторов частот, высокоскоростной передачи видео и т. д. - переписать всё на Си будет быстрее, чем пытаться хоть как-то заставить работать Java.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 3)
Ответ на: комментарий от mklord

Для людей в теме - да, элегантно. Любой нормальный эмбедщик знает наизусть лимиты всех типов данных и для него переполнение такой же математический закон, как скажем ассоциативность или коммутативность. Он просто мыслит в этой математике и легко может защититься от переполнения, когда оно не нужно и использовать его, когда оно нужно. А ещё он держит в голове примерный ассемблерный код, который генерит каждая сишная команда (ну хотя бы чтобы оценить каких конструкций стоит избегать).

А между тем это позволяет выжимать из контроллера гораздо больше на многих задачах. И, как я уже сказал, лучше заплатить в 2 раза больше программисту, чем поставить контроллер в 2 раза дороже на миллионах устройств. Чистая экономика.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Пилить будут на том, что умеет текущая команда; а уж если экономят на контроллерах, то и на программисте свой гешефт тоже будет оформлен.

Миллионные тиражы, убер-квалификация одного инженера, немерянные зарплаты в embedded — это все сказки для первокурсников.

Эффективность C и ассемблера, конечно, тоже роляют, но гораздо важнее, что это тупо древняя и устоявшаяся практика. Экспериментировать и делать свой стек никто не будет, даже если найдутся технологии получше. Например, были новости про компиляторы общего кода (не на C) в FPGA, и где они? А фиг знает, нету их.

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

И под Android колбасят тоже на Java. Потому что сложные штуки (а UI, сеть и мультимедиа — именно что сложные) на ней сделать проще и безопаснее, чем на C.

anonymous
()
Ответ на: комментарий от KivApple

Это было элегантно полвека назад. В C++ (и, видимо, в C) переполнение — undefined behevior, так что компилятор может там городить любой трэш. Но, скорее, завернет свои улучшалки, и «нормальный эмбедщик» однажды получит неожиданный баг. Проблема на x86_64: https://habrahabr.ru/company/pvs-studio/blog/276657/ .

И вуаля — сегодня работает, обновил компилятор, завтра уже не работает. Ты поставил свои оптимизации, компилятор — свои, а вместе получилась бяка.

Лучше бы код вменяемый пилили, чем такие оптимизации.

И да. Сколько из твоих знакомых программистов знает, во что превратится сложение двух int64_t на восьмибитной AVR-ке?

anonymous
()
Ответ на: комментарий от anonymous

Там же в комментах к статье пишут, что неопределенно только переполнение signed int, а переполнение unsigned int вполне соответствует стандарту и не вызывает сюрпризов. Так что использовать его для оптимизаций вполне допустимо. А я речь вёл как раз про него.

В отличии от беззнаковых переменных технически знаковость может быть реализована по-разному. Совсем не обязательно это будет дополнительный код (хотя почти везде так). А значит переполнение приведёт к разным результатам на разных архитектурах даже без каких-то оптимизаций компилятора.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от KivApple

Да, про uint я не заметил (да и не знал). И все равно — такой подход как-то не очень. Одна буква до плавучего бага — совсем не айс. И экономии все равно что никакой. А если есть существенная, то пусть лучше C-шный компилятор ее реализует.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.