|
Функция sprintf |
|
|
|
Jul 4 2018, 09:41
|
Частый гость
 
Группа: Участник
Сообщений: 167
Регистрация: 24-12-08
Из: Россия
Пользователь №: 42 714

|
Добрый день. Работаю на NXP MK66FN2M0xxx18. При этом при использовании функции sprintf для вывода чисел с плавающей запятой, программа на этой функции вылетает. Убираешь %f (т.е. выводишь все кроме float'ов) - все работает. Кто сталкивался с подобным? На сайте IAR нашел следующее https://www.iar.com/support/tech-notes/gene...point-f-on-arm/Правда думается, что не о том.
--------------------
C уважением!
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 44)
|
Jul 4 2018, 10:49
|
Частый гость
 
Группа: Участник
Сообщений: 167
Регистрация: 24-12-08
Из: Россия
Пользователь №: 42 714

|
1. Операционок нет, для прерываний контекст сохраняется и восстанавливается автоматически.
2. "Стэк не выровнен на 8." - поясните плз что это значит? Стэк должен начинаться с адреса кратного восьми? или все элементы в стэке должны размещаться в нем с "шагом" кратном 8? Или еще как-то?
--------------------
C уважением!
|
|
|
|
|
Jul 5 2018, 19:29
|
Частый гость
 
Группа: Участник
Сообщений: 167
Регистрация: 24-12-08
Из: Россия
Пользователь №: 42 714

|
Цитата(scifi @ Jul 4 2018, 14:13)  Именно. Вернее, указатель стека при вызове внешних функций должен быть кратен 8, но если стек выравнен в начале, то в дальнейшем компилятор соблюдает эту кратность. Если нарушить, бывают чудеса в частности вокруг sprintf. Должно быть, как-то замешаны вычисления с double. Кстати, насчёт double. Если при инициализации программы не включен FPU, то при попытке его использования будет именно "улетать". Стек начинается с адреса кратного 8. При заходе в подпрограмму функции sprintf в регистре адреса число (почему-то) не кратное 8. Почему - фиг его знает. Переменная, в которую я запихиваю строчку при помощи функции sprintf - локальная, т.е. объявлена в той же функции, в которой я вызываю sprintf. Пока пришел к следующему: если переменную объявить глобально, то все работает. Однако объяснения этому всему пока нет. Уважаемые форумчане, есть мысли на этот счет?
--------------------
C уважением!
|
|
|
|
|
Jul 7 2018, 06:05
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
уверен там хардварный FPU. включите его Код #define CORTEX_M4_BLOCK 0xe000e000 #define CPACR *(unsigned long *)(CORTEX_M4_BLOCK + 0xd88) // Co-processor Access Control
//__enable_FPU(); CPACR |= (0xf << 20); // enable access to FPU а вообще sprintf монструозная функция для эмбедед. никогда не использовал ее.
|
|
|
|
|
Jul 21 2018, 09:57
|
Частый гость
 
Группа: Участник
Сообщений: 167
Регистрация: 24-12-08
Из: Россия
Пользователь №: 42 714

|
Цитата(Jenya7 @ Jul 7 2018, 09:05)  а вообще sprintf монструозная функция для эмбедед. никогда не использовал ее. Как же тогда делать? Давно просили - про "Программа вылетает": не знаю как это может помочь Hard fault HFSR 0E80
Сообщение отредактировал aBoomest - Jul 21 2018, 09:58
--------------------
C уважением!
|
|
|
|
|
Jul 21 2018, 11:10
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(aBoomest @ Jul 21 2018, 12:57)  Как же тогда делать?
Давно просили - про "Программа вылетает": не знаю как это может помочь Hard fault HFSR 0E80 Вы уверены что правильно считали HFSR?  Цитата(Jenya7 @ Jul 7 2018, 09:05)  а вообще sprintf монструозная функция для эмбедед. никогда не использовал ее. Ну и зря. Не такая она и монструозная.
Сообщение отредактировал Arlleex - Jul 21 2018, 11:11
|
|
|
|
|
Jul 24 2018, 09:14
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(aBoomest @ Jul 21 2018, 14:57)  Как же тогда делать? Код void Reverse(char *str, int len) { int i=0, j=len-1, temp; while (i<j) { temp = str[i]; str[i] = str[j]; str[j] = temp; i++; j--; } } int IntToStr(int x, char str[], int d) { int i = 0; while (x) { str[i++] = (x%10) + '0'; x = x/10; }
// If number of digits required is more, then // add 0s at the beginning while (i < d) str[i++] = '0';
Reverse(str, i); str[i] = '\0'; return i; } // Converts a floating point number to string. void FtoA(float n, char *res, int afterpoint) { // Extract integer part int ipart = (int)n;
// Extract floating part float fpart = n - (float)ipart;
// convert integer part to string int i = IntToStr(ipart, res, 0);
// check for display option after point if (afterpoint != 0) { if (ipart==0) res[i++] = '0'; res[i] = '.'; // add dot
// Get the value of fraction part upto given no. // of points after dot. The third parameter is needed // to handle cases like 233.007 fpart = fpart * pow(10, afterpoint);
IntToStr((int)fpart, res + i + 1, afterpoint); } }
|
|
|
|
|
Jul 24 2018, 11:40
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(Jenya7 @ Jul 24 2018, 15:23)  а что плохого если строки лежат во txt секции? Да если бы они лежали только в .text...
Сообщение отредактировал Arlleex - Jul 24 2018, 11:40
|
|
|
|
|
Jul 24 2018, 11:46
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Jenya7 @ Jul 24 2018, 14:23)  а что плохого если строки лежат во txt секции? В какой txt-секции? Так как Вы пишете, все Ваши строки и указатели на них лежат в ОЗУ + инициализирующие значения лежат во флешь. А если передаёте в некую функцию строку типа: Func("си_не_знаю_пишу_как_попало") и эта Func объявлена как Func(char *), то такой вызов говорит компилятору до вызова функции создать переменную char t[] = "си_не_знаю_пишу_как_попало"; где-то в ОЗУ - или на стеке или в static памяти, проинициализировав её в runtime из константы char const ti[] = "си_не_знаю_пишу_как_попало"; во флешь.
|
|
|
|
|
Jul 24 2018, 12:54
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (scifi @ Jul 24 2018, 15:26)  Нет, не так. Явным приведением типа можно отсечь от указателя const, и компилятор не пикнет. Это жульничество, от такого компилятор не защищает. Вы напрасно спорите с jcxz, он прав. Более того, gcc уже давно ругается на char * text = "слава мне, победителю драконов"; QUOTE warning: ISO C++ forbids converting a string constant to ‘char*’
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 24 2018, 13:04
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Сергей Борщ @ Jul 24 2018, 15:54)  Вы напрасно спорите с jcxz, он прав. Нет, не напрасно. Я спорю вот с этим: Цитата(jcxz @ Jul 24 2018, 14:46)  А если передаёте в некую функцию строку типа: Func("си_не_знаю_пишу_как_попало") и эта Func объявлена как Func(char *), то такой вызов говорит компилятору до вызова функции создать переменную char t[] = "си_не_знаю_пишу_как_попало"; где-то в ОЗУ - или на стеке или в static памяти Это очевидное заблуждение.
|
|
|
|
|
Jul 24 2018, 13:11
|
Местный
  
Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140

|
Цитата(scifi @ Jul 24 2018, 16:04)  Это очевидное заблуждение. Вы правы. У меня в проекте вся менюшка выполнена в стиле lcd.Printx(0, " си_не_знаю_пишу_как_попало ");, где void Printx(uint8_t x,char *s);. Заглядываем в map по модулю меню. Код Module ro code ro data rw data ------ ------- ------- ------- Menu.o 2 436 7 20
|
|
|
|
|
Jul 24 2018, 13:49
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Jul 24 2018, 15:26)  Нет, не так. Явным приведением типа можно отсечь от указателя const, и компилятор не пикнет. Копию в ОЗУ точно не будет создавать. Ну я вообще-то говорю не про явное приведение типа. А когда вообще без приведения типа функции, принимающей указатель на переменную, передаётся константа. Явным приведением типа программист просто говорит, что в данном конкретном случае здесь передаётся "не то что можно ожидать по типу объявленного символического имени, а нечто другое". Если функция использует принятый указатель только для операций чтения, то при объявлении такой функции надо этому указателю (аргументу) назначать модификатор const. Частный случай - член-функция класса, использующая члены класса только на чтение (и вызывающая только const член-функции класса) - тоже должна объявляться с модификатором const. Если функция использует принятый аргумент-указатель и для операций записи, то тогда нужно описывать без слова const. И компилятор, при передаче аргумента такой фукции, будет проверять чтобы const-указатели не передавались в не-const аргументы функций. Цитата(VladislavS @ Jul 24 2018, 16:11)  Вы правы. У меня в проекте вся менюшка выполнена в стиле lcd.Printx(0, " си_не_знаю_пишу_как_попало ");, где void Printx(uint8_t x,char *s);. Заглядываем в map по модулю меню. Значит Ваш компилятор в этом случае не проверяет соответствие типов передаваемых данных и аргументов функции. И плохо. Это его недостаток. Но это не значит что все компиляторы так делают. Цитата(scifi @ Jul 24 2018, 16:04)  Это очевидное заблуждение. Почему? В чём разница между: char t[] = "XXXX"; и void Func(char *) ? И первом случае Вы говорите компилятору, что хотите иметь переменную (с начальным значением), а значит - хотите иметь возможность записи в неё. И во-втором случае говорите ему, что функция Func() хочет иметь возможность записи в принимаемый ею аргумент (т.е. - она принимает указатель на переменную). В чём принципиальная разница?
|
|
|
|
|
Jul 24 2018, 14:23
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(jcxz @ Jul 24 2018, 16:49)  Значит Ваш компилятор в этом случае не проверяет соответствие типов передаваемых данных и аргументов функции. И плохо. Это его недостаток. На самом деле типы соответствуют. Строковая константа имеет тип char[] без всяких const (сюрприз!), поэтому всё нормально. Это в C так, этот курьёз оставили, предположительно, из-за того, что к моменту изобретения const уже настрогали кучу кода, ломать его не хотелось. В то же время менять эту строку нельзя, поэтому компилятор мог бы предупреждать, но не по причине несоответствия типов, а по смыслу. В C++ всё проще: строка таки имеет тип const char[]. Цитата(jcxz @ Jul 24 2018, 16:49)  Почему? Вообще в данном случае ничто не запрещает компилятору создать копию строки в ОЗУ перед вызовом функции. Просто он этого не делает (и хорошо, зачем лишнюю работу делать?). Предлагаю собрать небольшой пример и заглянуть в листинг дизассемблера.
|
|
|
|
|
Jul 25 2018, 06:03
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Jul 24 2018, 17:23)  Вообще в данном случае ничто не запрещает компилятору создать копию строки в ОЗУ перед вызовом функции. Просто он этого не делает (и хорошо, зачем лишнюю работу делать?). Хотя-бы потому, что это - идеологически было бы правильно. Имхо: если функция только читает данные из переданного ей указателя - объявляй такой указатель с const, если и пишет - без const. А дальше - компилятор должен проверить соответствие типов и предупредить об ошибке. Что является только плюсом в отладке и уменьшении багов. Ну или автоматом устранить её, создав временный не-const объект на стеке или в static памяти. Ещё б желательно чтобы первое или второе поведение - определялось ключом компилятора. А то, что почти все быдлокодеры будут писать без const и передавать туда константы - так это их проблемы. Цитата(scifi @ Jul 24 2018, 17:23)  Предлагаю собрать небольшой пример и заглянуть в листинг дизассемблера. PS: Я уже проверял. Для IAR.
|
|
|
|
|
Jul 25 2018, 07:38
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Jul 25 2018, 10:05)  Я довольно хорошо изучил язык Си, и мне он кажется вполне логичным и непротиворечивым. Что-ж тут логичного, если char const t[] = "..."; Func(char *); Func(t); - вызывает ошибку, а Func("..."); - не вызывает? Но при этом 2-й вариант хоть и компилируется, но может приводить к неработоспособному коду. Хотя и в том и в другом случае данные одного и того же типа char const []. И даже более того - компилятор (линкёр?) могут объединить эти две константы в один объект в памяти.
|
|
|
|
|
Jul 25 2018, 11:13
|
Местный
  
Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140

|
Цитата(jcxz @ Jul 24 2018, 16:49)  Значит Ваш компилятор в этом случае не проверяет соответствие типов передаваемых данных и аргументов функции. И плохо. Это его недостаток. Чего это он мой? Забери его себе  Цитата(jcxz @ Jul 24 2018, 16:49)  Но это не значит что все компиляторы так делают. GCC и IAR компилят одинаково. Какой ещё эталон нужен? Они передают в функцию const char* и если внутри работать как с char *, то матерятся. Код void Printx(const uint8_t x,const char *s) { const char *c; Goto(x); if (!(c=s)) return; while (*c) { WriteData(codepage[(uint8_t)*c]); c++; } } Вот в IAR AVR, с его кривой памятью, можно управлять процессом, кстати.
|
|
|
|
|
Jul 25 2018, 11:46
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(VladislavS @ Jul 25 2018, 14:13)  Они передают в функцию const char* и если внутри работать как с char *, то матерятся. Вы не поняли. Разговор о случае если аргумент функции - char *, а передаваемое значение: Func("xxx") (char const *). То компилятор не ругается. А по уму должен бы. См. посты выше и https://electronix.ru/forum/index.php?showt...t&p=1574877
|
|
|
|
|
Jul 25 2018, 11:51
|
Местный
  
Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140

|
Ещё как ругается. Если в Print(char *s); передать Print(" ");, то много нового о себе от компилятора узнаете. Ругается, правда, только варнингом. Как и GCC
В IAR это звучит как Код Warning[Pe2464]: conversion from a string literal to "char *" is deprecated Menu.cpp 54
|
|
|
|
|
Jul 25 2018, 12:24
|
Местный
  
Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140

|
Цитата(jcxz @ Jul 25 2018, 15:16)  Как Вы добились сего??? Версия IAR? какие ключи компиляции? Перепроверил ещё раз. 8.22.2 выдаёт варнинг, и 8.30.1 соответственно тоже. Младше у меня нет. Проект С++ с настройками по умолчанию.
|
|
|
|
|
Jul 25 2018, 12:27
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(scifi @ Jul 25 2018, 11:25)  Компилируйте в режиме C++, ни в чём себе не отказывайте  Цитата(jcxz @ Jul 25 2018, 15:16)  Как Вы добились сего??? Версия IAR? какие ключи компиляции? Цитата(VladislavS @ Jul 25 2018, 15:24)  Проект С++ с настройками по умолчанию. Цитата(jcxz @ Jul 25 2018, 13:18)  И...? У меня и так C++. Очевидно, у вас таки не включен режим С++
|
|
|
|
|
Jul 25 2018, 15:42
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ Jul 25 2018, 15:27)  Очевидно, у вас таки не включен режим С++ 
ку? Расширение си-файлов тоже: .cpp. Без скриншота поверите?  Цитата(VladislavS @ Jul 25 2018, 15:24)  Перепроверил ещё раз. 8.22.2 выдаёт варнинг, и 8.30.1 соответственно тоже. Младше у меня нет. Проект С++ с настройками по умолчанию. Ясно. У меня 7.80.4. Есть ещё 8.20 - завтра может проверю. А всё что выше 8.22 - ставить не рискую. Почему - тема была тут: https://electronix.ru/forum/index.php?showt...=147939&hl=
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|