Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR AVR функция strstr
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
SZ0
Код
u8 str_buff[100];
c8 __flash *OKin = "OK";

if(strstr((const c8 *)str_buff,(const c8 *)OKin)return 0;


strstr всегда выдаёт указатель на начало буфера, даже если ОК там нет. Т.е. в начале буфера могут быть любые символы, а потом ОК. Как я понимаю, не правильно преобразовываю. Но не могу понять, как правильно преобразовать типы. Сам массив в озу, а строки в нём ищутся из flash.
Xenia
Цитата(SZ0 @ Jul 22 2010, 21:02) *
Как я понимаю, не правильно преобразовываю. Но не могу понять, как правильно преобразовать типы. Сам массив в озу, а строки в нём ищутся из flash.

Функция strstr() работает только на нормальной памяти (RAM), но не на flash. А уж тем более не может работать, когда один аргумент во flash, а другой в RAM. Таковы уж издержки гарвардской архитектуры.
Поэтому обман этой функции с помощью переименования типов указателей у вас не пройдет. Функция не заработает, поскольку на такую ситуацию она не рассчитана.
Поэтому скопируйте лучше flash в RAM, например, с помощью функции strcpy_P(), а потом уже запускайте strstr() на полностью RAM-строках. Хотя слово "ОК" настолько коротко, что проще его завести сразу в RAM, потери будут минимальными.
zltigo
QUOTE (Xenia @ Jul 22 2010, 21:36) *
Таковы уж издержки гарвардской архитектуры....

....в самых простейших ее реализациях, например, AVR от Atmel. По нынешним временам так ломово контроллеры, даже если их и называют гаввардскими, уже не делают.


Xenia
Цитата(zltigo @ Jul 22 2010, 22:10) *
....в самых простейших ее реализациях, например, AVR от Atmel.

Ну вот опять Atmel у вас оказался виноват smile.gif

Цитата(zltigo @ Jul 22 2010, 22:10) *
По нынешним временам так ломово контроллеры, даже если их и называют гаввардскими, уже не делают.

Это проблема не столь аппаратная, сколько логическая. Указанная проблема будет возникать во всех случая, когда числовой адрес памяти не уникален. Т.е. тогда, когда существует более одного адресных пространств, в которых имеется своя собственная нумерация. При этом числового значения указателя оказывается недостаточно для того, чтобы однозначно определить, к какого рода памяти он относится.
Очевидно, совершенно та же самая проблема возникнет, если вместо указателя на flash-память использовать указатель на eeprom-память. В этом случае функция strstr() тоже откажется работать правильно. Точнее говоря, она-то отработает правильно, только символы возьмет не из той памяти, которую хотелось бы.
А гарвардская архитетура тут только при том, что во многих своих реализациях допускает наличие двух адресных пространств (памяти программ и памяти данных), которые допускают перекрытие по номерам ячеек. Но если оба вида памяти разместить в одном адресном пространстве без перекрытия, то указанная проблема исчезнет. Как, например, не возникает такая проблема у компьютеров IBM PC, у которых в младших адресах расположено ПЗУ, а выше его ОЗУ.
Однако в тех случаях, когда команды обращения к ОЗУ и ПЗУ разные, указанная проблема встает в полный рост. И тут разделением адресов горю не поможешь. Хочешь, не хочешь, а код функций, работающих с разными видами памяти, окажется тоже разным. Поэтому сишным переопределением типа указателей проблема не решается.
А гарвардская архитектура становится виноватой smile.gif в тот самый момент, как только у процессора появляются РАЗНЫЕ команды обращения к ОЗУ и к ПЗУ. В тех же случаях, когда между этими обращениями нет разницы, подобная проблема не возникает.
SZ0
Спасибо за разъяснение. Придётся искомые строки в озу перетаскивать.
_Bill
Цитата(Xenia @ Jul 23 2010, 00:52) *
Ну вот опять Atmel у вас оказался виноват smile.gif
Но если оба вида памяти разместить в одном адресном пространстве без перекрытия, то указанная проблема исчезнет. Как, например, не возникает такая проблема у компьютеров IBM PC, у которых в младших адресах расположено ПЗУ, а выше его ОЗУ.

Именно этим меня STM8 и привлекает. У него программа может одинаково работать как из ОЗУ, так и из памяти программ.
zltigo
QUOTE (Xenia @ Jul 22 2010, 23:52) *
Ну вот опять Atmel у вас оказался виноват smile.gif

Я этого не говорил. Большинство простых контрроллеров 80x-90x прошлого века такие. Если хочется искать виноватых, то виновато время которое течет. Люди и фирмы, которые "вчера" делали свою работу хорошо ничуть не виноваты.
QUOTE
А гарвардская архитетура тут только при том, что во многих своих реализациях допускает наличие двух адресных пространств (памяти программ и памяти данных),

Не во многих, а во всех и не адресных пространств, а шин. Все остальное вторично. В том числе "команды обращения к ОЗУ и ПЗУ разные" и это уже не гарвард "виноват", а то, что так было явно проще делать контроллер.
QUOTE
Как, например, не возникает такая проблема у компьютеров IBM PC, у которых в младших адресах расположено ПЗУ, а выше его ОЗУ.

1. x86 неймановсий и ему глубоко все равно где и что расположено физически, кроме:
2. x86 один из процессоров стартующих не с нулевого адреса. Посему ПЗУ в конце первого мегабайта, а не на "младших адресах".
SZ0
Строки пришлось определить так:
Код
const c8 OKin[] = "OK";

Строки находятся теперь и в flash и в озу, куда копируются при инициализации. Т.к. проц толстый и кол-во искомых строк немного, то не напрягает. Но вот если у проца озу маленькое, как тогда быть? К выбору другого проца пока не прибегаем smile.gif
zltigo
QUOTE (SZ0 @ Jul 23 2010, 09:02) *
Но вот если у проца озу маленькое, как тогда быть?

Писать свои функции. Можно по мотивам библиотечных.

mempfis_
Цитата(zltigo @ Jul 23 2010, 09:18) *
Писать свои функции. Можно по мотивам библиотечных.


+1
Столкнулся с подобной проблемой когда из-за излишнего применения const было съедено много оперативки для константных строк.
По аналогии с библиотечной strstr написал свою ф-ию для поиска подстроки в строке с различными комбинациями типов строк ((sram, sram), (sram, flash), (sram, eeprom)) - пользуюсь уже в 4м проекте.

Код
/***************************************************************************/
//поиск подстроки в строке с ограничением по длине поиска
signed int my_strstr(unsigned char *pData, unsigned char __flash *pComp, unsigned int len)
{
  signed int result=-1;

  for( unsigned int i=0; i<len; i++)
  {
    result=1;
    for( unsigned int j=0; *(pComp+j); j++)
    {
      if( ( *(pData+i+j) != *(pComp+j))  || ( !*(pComp+j)) )
      {
        result=-1;
        break;
      }
    }

    if(result == 1)
    {
      return i; //возвращаем позицию начала подстроки в строке
    }
  }

  return -1;
}
/******************************************************************/

IgorKossak
QUOTE (zltigo @ Jul 23 2010, 09:18) *
Писать свои функции. Можно по мотивам библиотечных.

+1
Я в подобном случае написал шаблонную функцию (С++) и copy-paste делать не пришлось.
Xenia
Цитата(SZ0 @ Jul 23 2010, 09:02) *
Строки пришлось определить так:
Код
const c8 OKin[] = "OK";

Строки находятся теперь и в flash и в озу, куда копируются при инициализации. Т.к. проц толстый и кол-во искомых строк немного, то не напрягает. Но вот если у проца озу маленькое, как тогда быть? К выбору другого проца пока не прибегаем.

Знаю два варианта решения вашей проблемы:

1) Завести себе в ОЗУ "мусорную" строку, которая будет использоваться сразу под множество целей. Тогда не "OK" там постоянно будет лежать, а разные вещи, по мере надобности. Или скажем sprintf() на эту строку будет работать. Или чтобы какие-то сообщения там формировать. Короче говоря, создаете себе буфер на вывод, а используете его не всегда по назначению, но и для ОЗУвления ПЗУшных констант smile.gif.

2) Более элегантный метод, в котором необходимое для дела место в ОЗУ временно занимается у стека. Для этого создайте блок и заводите в нем место для временной строки:

Код
c8 __flash *OKin = "OK";
.............
main()
{
.............
  {  // открываем блок
     char ozu[3];  // создаем локальный массив на стеке, принадлежащий ОЗУ
     strcpy_P( ozu, OKin); // копируем строковую константу из ПЗУ в ОЗУ
     result = strstr( str_buff, ozu);  // выполняем функцию strstr() полностью на ОЗУшных аргументах
  }  // закрываем блок, в результате чего локальный массив ozu[] исчезнет, вернув свою память стеку
............
}
mempfis_
Код
Знаю два варианта решения вашей проблемы:

1) Завести себе в ОЗУ "мусорную" строку, которая будет использоваться сразу под множество целей...

2) Более элегантный метод, в котором необходимое для дела место в ОЗУ [b]временно занимается[/b] у стека...


Каждый из этих вариантов предполагает предварительное копирование искомой подстроки в ОЗУ и тольком потом вызов ф-ции strstr для поиска в строке скопированной подстроки.
Для поиска "ОК" сойдёт. А если возможных подстрок будет 100-200 (например реализация поддержки АТ-интерфейса или своего интерфейса управления с кучей команд).
Разумно будет написать свою ф-ию которая будет сравнивать буффер со строкой во flash. Сложностей никаких. В качестве бонуса сократится время на поиск подстроки и уменьшится размер кода программы и использованной оперативки.
_Bill
Цитата(mempfis_ @ Jul 23 2010, 10:46) *
+1
Столкнулся с подобной проблемой когда из-за излишнего применения const было съедено много оперативки для константных строк.
По аналогии с библиотечной strstr написал свою ф-ию для поиска подстроки в строке с различными комбинациями типов строк ((sram, sram), (sram, flash), (sram, eeprom)) - пользуюсь уже в 4м проекте.

Код
//поиск подстроки в строке с ограничением по длине поиска
signed int my_strstr(unsigned char *pData, unsigned char __flash *pComp, unsigned int len)
{
  signed int result=-1;

  for( unsigned int i=0; i<len; i++)
  {
    result=1;
    for( unsigned int j=0; *(pComp+j); j++)
    {
      if( ( *(pData+i+j) != *(pComp+j))  || ( !*(pComp+j)) )
      {
        result=-1;
        break;
      }
    }

    if(result == 1)
    {
      return i; //возвращаем позицию начала подстроки в строке
    }
  }

  return -1;
}

Я думаю, вашу функцию можно чуть-чуть эффективней сделать.
Код
signed int my_strstr(unsigned char *pData, unsigned char __flash *pComp, unsigned int len)
{
  char result=0;

  for( unsigned int i=0; i<len; i++)
  {
    result=1;
    for(char *tp = pData+i; *pComp; tp++, pComp++)
    {
      if(!*pComp  ||  *tp != *pComp)
      {
        result=0;
        break;
      }
    }

    if(result)
    {
      return i; //возвращаем позицию начала подстроки в строке
    }
  }

  return -1;
}
Или нет?
_Bill
Я думаю, вашу функцию можно чуть-чуть эффективней сделать.
Код
signed int my_strstr(unsigned char *pData, unsigned char __flash *pComp, unsigned int len)
{
  char result=0;

  for( unsigned int i=0; i<len; i++)
  {
    result=1;
    for(char *dp=pData+i, char __flash *pp=pComp; *pp; dp++, pp++)
    {
      if(!*pp  ||  *dp!=*pp)
      {
        result=0;
        break;
      }
    }

    if(result)
    {
      return i; //возвращаем позицию начала подстроки в строке
    }
  }

  return -1;
}
Или нет?
PS: В предыдущем сообщении ошибка. Не знаю как его удалить.
Xenia
_Bill, похоже на то, что ваш алгоритм даст неправильный ответ, если обе строки изначально тождественны. При этом, когда flash-строка дойдет до своего нуля, rеsult обнулится (сработает условие !*pp), отбросив этот вариант, как не являющийся совпадением - а это неправильно.
_Bill
Цитата(Xenia @ Jul 24 2010, 00:14) *
_Bill, похоже на то, что ваш алгоритм даст неправильный ответ, если обе строки изначально тождественны. При этом, когда flash-строка дойдет до своего нуля, rеsult обнулится (сработает условие !*pp), отбросив этот вариант, как не являющийся совпадением - а это неправильно.

Хм... За правильность алгоритма не ручаюсь. Я только формально скорректировал существующий - заменил индексы на указатели, тип и значения вспомогательной переменной. Не более того. Возможно единственно, что может повлиять на правильность работы, так это изменение порядка проверки условия совпадения символов в строках. Тогда я неправ.
PS: Да, тут я действительно неправ. Посчитал не существенным порядок проверки.
zltigo
Классический, писанный на 'C', strstr()
CODE
/*                      - STRSTR.C -

   The ANSI "strstr" function.

   $Revision: 38615 $

   Copyright 1986 - 1999 IAR Systems. All rights reserved.
*/

#include "string.h"

char *strstr(const char *s1, const char *s2)
{
  int n;

  if (*s2)
  {
    while (*s1)
    {
      for (n=0; *(s1 + n) == *(s2 + n); n++)
      {
        if (!*(s2 + n + 1))
          return (char *)s1;
      }
      s1++;
    }
    return NULL;
  }
  else
    return (char *)s1;
}

от него и плясать.
desh
Я использую функцию которая работает одновременно со строками расположенными как в памяти программ так и в памяти данных. А для того что строки автоматически помещались во flash использую опцию компилятора --string_literals_in_flash. Из недостатков этого метода обнаружил что сама функция требует не мало памяти программ.

CODE

//******************************************************************************
// Функция сравнения строк
//******************************************************************************
char __generic* strstr_G(char __generic* buf, char __generic* sub)
{
if (*sub)
{
while (*buf)
{
char __generic* bp = buf;

do
{
if (!*sub) return buf;
}
while (*bp++ == *sub++);
sub -= (unsigned long) bp;
sub += (unsigned long) buf;
buf += 1;
}
return NULL;
}
return buf;
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.