Easyelectronics.ru

Электроника для всех
Текущее время: 21 июн 2018, 11:25

Часовой пояс: UTC + 5 часов



    • JLCPCB - Платы прототипов всего за 2$ c бесплатной доставкой (при первом заказе)
    • 10 PCBs за $2 для 2 слоев, $15 для 4 слойной, $74 для 6 слойной платы.
    • Крупнейший китайский производитель прототипных плат. 290000+ клиентов & 8000+ заказов в день!
    • LCSC - Крупнейший китайский онлайн магазин радиодеталей.

Начать новую тему Ответить на тему  [ Сообщений: 37 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 13:45 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
Код:
    int i;
    char *str1;
    char *str2

    str1 = "ABC";
    str2 = "DEF";
    i = strlen(str1);
    sprintf(&str1[i], "+%s", str2);


Компилирую в KEIL для ARM.
В результате работы sprintf не изменяет значение str1.
В чём может быть засада? Сломал голову уже за три дня. Просто в borland C++ работает без проблем! В долбаном KEIL-е не работает! о_О

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:02 
Старожил

Зарегистрирован: 18 фев 2010, 12:47
Сообщения: 310
Откуда: г. Челябинск
а память выделяется нормально под str1 ? Просто &str1[strlen(str1)] указывает на область память ПОСЛЕ строки str1 (если я ничего не путаю) - а там может быть что угодно, в том числе другая переменная.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:12 
Супермодератор
Аватара пользователя

Зарегистрирован: 28 янв 2010, 05:47
Сообщения: 1031
Откуда: Винница
shum_inc писал(а):
а память выделяется нормально под str1 ? Просто &str1[strlen(str1)] указывает на область память ПОСЛЕ строки str1 (если я ничего не путаю) - а там может быть что угодно, в том числе другая переменная.


Чисто теоретически &str1[strlen(str1)] указывает на \0, который завершает строку str1.
Но вопрос в другом - оно выделяет память само или в str1 уже должно быть достаточно места для этого?

_________________
Show


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:19 
Старожил

Зарегистрирован: 18 фев 2010, 12:47
Сообщения: 310
Откуда: г. Челябинск
угу, нужен полный код


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:20 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
shum_inc писал(а):
а память выделяется нормально под str1 ? Просто &str1[strlen(str1)] указывает на область память ПОСЛЕ строки str1 (если я ничего не путаю) - а там может быть что угодно, в том числе другая переменная.


У меня тоже была мысль по поводу памяти. Но в процессе выполнения программы значение переменной str1 я изменяю. И всё в неё нормально помещается. А вот функция sprintf никак не хочет туда ничего запихивать.

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:23 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
shum_inc писал(а):
угу, нужен полный код


Что еще из кода нужно?
Пробовал создавать чистый проект, из кода только то, что я выше привёл. Не пашет.
Стартап стандартный КЕЙЛ-овский для sam7.
Сам компилятор полный, не демка.

Ну естественно все инклады и прочие скобки на месте
Код:
   
#include <stdio.h>
#include <string.h>

int i;
char *str1;
char *str2

void main(void)
{
    str1 = "ABC";
    str2 = "DEF";
    i = strlen(str1);
    sprintf(&str1[i], "+%s", str2);
}

_________________
Hacked by ICE


Последний раз редактировалось adrenocrome 13 апр 2010, 14:26, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:23 
Супермодератор
Аватара пользователя

Зарегистрирован: 28 янв 2010, 05:47
Сообщения: 1031
Откуда: Винница
У борланда своеобразное отношение к стандартам, у кейла хз.
Цитата:
int sprintf(char* s, const char* format, ...);
Like fprintf, but output written into string s, which must be large enough to hold the output, rather than to a stream. Output is NUL-terminated. Returns length (excluding the terminating NUL).

_________________
Show


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:30 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
xrayman писал(а):
У борланда своеобразное отношение к стандартам, у кейла хз.
Цитата:
int sprintf(char* s, const char* format, ...);
Like fprintf, but output written into string s, which must be large enough to hold the output, rather than to a stream. Output is NUL-terminated. Returns length (excluding the terminating NUL).


Самое интересное, что в некоторых примерах переменные объявлены именно так как у меня.
Вот у Элм-Чена того-же например
http://elm-chan.org/fsw/ff/en/readdir.html
Причём в программе размер переменной ,указатель на которую передаётся функции, так же не задан.

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 14:51 
Супермодератор
Аватара пользователя

Зарегистрирован: 28 янв 2010, 05:47
Сообщения: 1031
Откуда: Винница
adrenocrome писал(а):
Самое интересное, что в некоторых примерах переменные объявлены именно так как у меня.
Вот у Элм-Чена того-же например
http://elm-chan.org/fsw/ff/en/readdir.html
Причём в программе размер переменной ,указатель на которую передаётся функции, так же не задан.


А где там программа, которая использует эту функцию? Я не нашел :(

_________________
Show


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 15:05 
Только пришел

Зарегистрирован: 05 фев 2010, 13:01
Сообщения: 26
adrenocrome писал(а):
Код:
    int i;
    char *str1;
    char *str2

    str1 = "ABC";
    str2 = "DEF";
    i = strlen(str1);
    sprintf(&str1[i], "+%s", str2);


Компилирую в KEIL для ARM.
В результате работы sprintf не изменяет значение str1.
В чём может быть засада? Сломал голову уже за три дня. Просто в borland C++ работает без проблем! В долбаном KEIL-е не работает! о_О


Проблема в некорректном коде. То, что в одном компиляторе работает - это не показатель.

Пишите так :


char str0[20];
char str1[] = "ABC";
char str2[]= "DEF";


sprintf( str0, "%s + %s", str1,str2 );


Должно работать в любом компиляторе

Если же Вам нужно сложить две строки, то для этого существует ф-ция strcat()


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 15:20 
Старожил

Зарегистрирован: 18 фев 2010, 12:47
Сообщения: 310
Откуда: г. Челябинск
Думается мне тут принципиальная ошибка всё же.
1. Если Вы хотите склеить две строки - тут верно предложили strcat
2. Используя sprintf и пр. с указателями - следите за памятью, т.к. :
- str1 у вас - указатель на первый символ
- &str1[i] указывает на байт ПОСЛЕ последнего символа (по сути "в никуда" или "куда попало", т.к. место ЗА str1 никто явно не резервирует) - уже тут ошибка, несмотря на то что иногда это может и будет работать. В этом случае место нужно резервировать запасом - как раз как в примере из поста выше


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 15:26 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
shum_inc писал(а):
2. Используя sprintf и пр. с указателями - следите за памятью, т.к. :
- str1 у вас - указатель на первый символ
- &str1[i] указывает на байт ПОСЛЕ последнего символа (по сути "в никуда" или "куда попало", т.к. место ЗА str1 никто явно не резервирует) - уже тут ошибка, несмотря на то что иногда это может и будет работать. В этом случае место нужно резервировать запасом - как раз как в примере из поста выше


Да, вот я уже тоже об этом подумал. Попробую явно указать размер.

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 15:31 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
xrayman писал(а):
А где там программа, которая использует эту функцию? Я не нашел :(


Облажался я немного =)
У Чена нет примеров, у какого-то шибко умного немца есть.
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/arm_memcards/index.html
Там вобщем прикручивается SD карточка и FAT к АРМу.
Уже вроде направили на путь истинный, буду пробовать. Видимо, ошибка у меня всёж. Неправильно понял принцип выделения памяти.

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 15:35 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
dev3 писал(а):

Пишите так :


char str0[20];

Вот тут видимо и была моя проблема - необходимо жёстко задать размер.

dev3 писал(а):
Если же Вам нужно сложить две строки, то для этого существует ф-ция strcat()

Мне нужно было разобраться со sprintf, почему работает в одном компиляторе и не работает в другом. Про strcat знаю =)

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 16:11 
Только пришел

Зарегистрирован: 05 фев 2010, 13:01
Сообщения: 26
Ошибка в том, что Вы вообще не выделяете память.

Но Borland C++ умный, он догадался что нужно сделать и выделил целый вагон памяти . Включите опцию выводить все предупреждения в Borland C++ и он обязательно выругается.

int i;
char *str1;// объявили указатель на char
char *str2// то же

str1 = "ABC";// присваиваем указателю( адресу) строку символов
str2 = "DEF";// то же

Тут Borland C++ догадался вместо Вас выделить память и присвоить Вашим указателям str1 и str2
адреса выделенных буферов памяти, скопировал туда символы "ABC"("DEF") и поместил символ конца строки \0 .

i = strlen(str1);// получилось 3

sprintf(&str1[i], "+%s", str2);// &str1[i] - адрес символа конца строки, туда копируется

"+DEF", поскольку Borland C++ памяти выделил с запасом

В результате все правильно получилось , в str1 находиться строка "ABC+DEF".
А компилятор "KEIL" не захотел вводить Вас в дальнейшее заблуждения и все Вам высказал :).

Вам нужно было воспользоваться ф-циями выделения памяти в языке С ( malloc,calloc ) или объявить массивы, тогда память выделилась бы автоматически


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 19:12 
Старожил

Зарегистрирован: 22 мар 2010, 22:54
Сообщения: 3996
ну вы, парни, даете, стока написали, а по сути нет.
дело вовсе не в sprintf. дело в том, что "ABC" - это const char. т.е. делая в билдере
char *x="ABC" вы присваиваете х адрес в секции данных, где находится "ABC". совершенно случайно этот адрес находится в озу и туда разрешена запись. и вы портите то, что трогать вообще не должны! никогда так не делайте (запись в константные строки) - испортите ЧУЖОЕ!!!
кейл же, видя, что это const, засовывает строку во флеш. где вы и пытаетесь ее менять.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 19:15 
Старожил

Зарегистрирован: 22 мар 2010, 22:54
Сообщения: 3996
dev3 писал(а):
Вам нужно было воспользоваться ф-циями выделения памяти в языке С ( malloc,calloc ) или объявить массивы, тогда память выделилась бы автоматически


нет, нужно было чтобы строка лежала в озу.
когда объявляется массив типа char x[n]="12345", то во флеше у вас будет сама эта строка, но при таком определении создастся массив в озу и туда эта строка скопируется.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 20:23 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1123
Откуда: Германия
Ink писал(а):
ну вы, парни, даете, стока написали, а по сути нет.
дело вовсе не в sprintf. дело в том, что "ABC" - это const char. т.е. делая в билдере
char *x="ABC" вы присваиваете х адрес в секции данных, где находится "ABC". совершенно случайно этот адрес находится в озу и туда разрешена запись. и вы портите то, что трогать вообще не должны! никогда так не делайте (запись в константные строки) - испортите ЧУЖОЕ!!!
кейл же, видя, что это const, засовывает строку во флеш. где вы и пытаетесь ее менять.


Без указания const строка ляжет в RAM, потому как это переменная типа pointer а не константа, (так как у автора топика как бы нету там никакого const), и указывает на область памяти. А длину области памяти никто кроме программиста не знает. (Потому то в С/С++ мало кто любит строки). Максимум, что делает компилятор - добавляет еще один байт и нолик туда вписывает.

Кстати, в АВРках указания const НЕ достаточно, чтобы переменная легла во FLASH, если в WinAVR компилите. Надо явно указывать хитрые макросы типа PSTR("String"). В АРМах может быть все по другому, еще толком не копал этого.

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 21:15 
Заглядывает иногда
Аватара пользователя

Зарегистрирован: 13 апр 2010, 13:44
Сообщения: 30
Вобщем спасибо всем,кто высказался.
Я её победил, указав в явном виде размер строкового массива.

_________________
Hacked by ICE


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 13 апр 2010, 21:16 
Старожил

Зарегистрирован: 22 мар 2010, 22:54
Сообщения: 3996
внимательнее: "ABC" имеет тип const char. а уж дальше можете делать свои указатели на него без const. для авр будет не конст, а типа прогмем или что еще...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 14 апр 2010, 12:16 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1123
Откуда: Германия
Ink писал(а):
внимательнее: "ABC" имеет тип const char. а уж дальше можете делать свои указатели на него без const. для авр будет не конст, а типа прогмем или что еще...


В том то дело, что НЕ будет это все в прогмем. Можете проверить.

Да. "ABC" это константа, но только для инициализации массива.

Компилятор при выражении

char * p = "ABC";

делает в РАМ массив в 4 байта, и помещает туда нашу константу "ABC". И вот с ЭТОГО момента поинтер p указывает не на константу, а на обычный массив в 4 байта в РАМе.

Можете проверить, откомпилив небольшую программку, и посмотреть, как это все в стартап коде копируется в РАМ из флеша. ;-)

У программиста нету никаких других связей с этим значением, кроме как указателя на РАМ, но никак не во флешь.
В С вроде как нет никаких обычных, "доступных" (естественно, возможно все, но это не входит в понятие "доступные"), возможностей добраться то того места, где именно лежит значение, которым инициализируется этот массив. Нужно знать архитектуру и то, как компилятор это все "проворачивает", насколько я понял.

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 14 апр 2010, 13:40 
Старожил

Зарегистрирован: 03 мар 2010, 14:10
Сообщения: 1514
Откуда: Беларусь, Минск
MasterAlexei писал(а):
Компилятор при выражении

char * p = "ABC";

делает в РАМ массив в 4 байта, и помещает туда нашу константу "ABC". И вот с ЭТОГО момента поинтер p указывает не на константу, а на обычный массив в 4 байта в РАМе.

Вот тут вы в корне заблуждаетесь.
ANSI C99 (ISO/IEC 9899:1999) page 130, §6.7.8 example 8
Цитата:
On the other hand, the declaration
char *p = "abc";
defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’
with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to
modify the contents of the array, the behavior is undefined.


То что вы описали делается выражением
char p[] = "ABC";


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 14 апр 2010, 15:08 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1123
Откуда: Германия
amx писал(а):
То что вы описали делается выражением
char p[] = "ABC";


Похоже, что я чего-то напутал. Но кажется, я где то в своих проектах уже встречал такое поведение, как я описывал, и дело было в том, что я МОГ изменить содержимое памяти, куда указывал поинтер. Сегодня дома вечерком попробую на AVRке и на ARM STM32ом.

Update:

Попробовал сейчас в симуляторе AVR.

char * pPointer = "ABCDEFG";
pPointer[0] = 'H';

pPointer указывает в SRAM !!!
Компилятор WinAVR ничего не сказал по этому поводу, откомпилился нормально.
В симуляции символ A заменился на символ H.

если приписать const в начало строки:
const char * pPointer = "ABCDEFG";
Компилятор ругается на присваивание:
pPointer[0] = 'H';
что идет попытка записи в константую область памяти.

При такой конструкции:

const char * pPointer = "ABCDEFG";
u08 abc = pPointer[0];

pPointer все равно лежит в SRAM! И никак не во Флаш. Но это, скорее всего момент реализации на конкретной архитектуре (AVR). ARM смогу только вечером попробовать.

Именно поэтому в то описании, что привели несколькими постами выше, сказано что запись в такую область будет неопределенной, так как зависит от конкретной реализации и архитектуры.

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 14 апр 2010, 17:19 
Старожил

Зарегистрирован: 22 мар 2010, 22:54
Сообщения: 3996
возможно это гцц хитрит. в CVAVR вроде как не прокатит сделать даже так: char * pPointer = "ABCDEFG", ибо "ABCDEFG" у него имеет тип char flash. но обычно на других платформах тип - const char. и в пике, и в арме оно располагается во флеш.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: засада со sprintf
СообщениеДобавлено: 14 апр 2010, 18:01 
Старожил

Зарегистрирован: 03 мар 2010, 14:10
Сообщения: 1514
Откуда: Беларусь, Минск
Ink писал(а):
возможно это гцц хитрит.
В стандарте языка не существует понятий флешь и рам - есть область констант и область переменных - а где все это добро располагается - отдаётся на откуп компиляторо-писателей. В gcc расположение во флешь сделано через макрос PROGMEM для авр (поправьте если не прав - никогда с авр дела не имел)- у других компиляторов - по другому, для других архитектур для gcc - ещё как-то.
Итого: что б писать качественный код надо точно знать как себя ведёт компилятор в таких "узких" местах - а это все довольно хорошо описывается в руководствах, которые по доброй славянской традиции читаются только когда что-то не работает. Займитесь чтением - будете меньше глупых вопросов задавать.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 37 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: jenya77


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB