Easyelectronics.ru

Электроника для всех
Текущее время: 25 ноя 2017, 07:07

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



    • 10 шт. 2-слоя 100*100mm 2$. Быстрый заказ: JLCPCB.com
    • JLCPCB - это крупнейшая фабрика PCB прототипов в Китае.
    • Имеющий более 290,000 клиентов и выполняющий более 8,000 заказов в день.
    • 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
Сообщения: 1026
Откуда: Германия
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
Сообщения: 1026
Откуда: Германия
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
Сообщения: 1026
Откуда: Германия
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 часов


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

Сейчас этот форум просматривают: нет зарегистрированных пользователей


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

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

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