Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: процедура с указателем на строку в памяти программ
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
chief_olimp
Здраствуйте. Ткните где не так кто знает пожалуйста
Код
unsigned char blabla[] = "blablabla";
/// текст и все такое
void find (unsigned char *findbuff)
{
    unsigned int i;
    while (*findbuff != '\0')
   {
    USART0_OutBuf[i++] = *findbuff;
    findbuff++;
   }
}
int main (void)
{
find (blabla);
}

т.е. программа какие то данные из ОЗУ грузит в процедуру и что то так с ними делает
Скажите пожалуйста как такое же провернуть со строкой типа
Код
unsigned char PROGMEM blabla[] = "blablabla";

Спасибо
rokhan
И что ты хочешь найти? smile.gif
Если ты хочешь найти строку в "блабла" в буфере... - тогда тебе надо цикл опирать на буфер а не на строку.
rezident
Цитата(chief_olimp @ Dec 24 2008, 19:39) *
Скажите пожалуйста как такое же провернуть со строкой типа
Код
unsigned char PROGMEM blabla[] = "blablabla";

Во-первых, строка должна заканчиваться завершающим нулем.
Код
unsigned char PROGMEM blabla[] = "blablabla\0";

А во-вторых, перед выводом нужно указателю присвоить значение ее адреса, явно сделав преобразование типа.
Код
findbuff=(unsigned char *)&blabla[0];
Tiro
Чип AVR с компилятором WinAVR?
Тогда прочтите здесь: Data in Program Space
chief_olimp
дело в том что я хочу каждый раз используя одну и ту же функцию искать разные строки подгружаемые из памяти программ. Функция ищет данные из FLASH в буфере UART. И если находит то сообщает об этом. Если считать данные одной функцией и потом сравнить два буффера то все получается. Проблема в том что я не знаю как объявить стоку из FLASH и затем данные из этой строки использовать в функции.
defunct
Цитата(chief_olimp @ Dec 24 2008, 18:49) *
Проблема в том что я не знаю как объявить стоку из FLASH и затем данные из этой строки использовать в функции.

Почитайте вот эту тему
http://electronix.ru/forum/index.php?showtopic=56157&hl=
может натолкнет на идеи.
WHALE
Я решал вашу задачу так:
Код
flash char *flash STRING_COMPARE[]={"BLA-BLA-BLA", "LY-LY-LY"};

char* COMPARE_STRING_RX(flash char *ptr_to_compare_rx) //не равны-возращается указательна NULL  
                                       {    
                        char*  ptr;                                                                    
    return ptr=strstrf(str_rx,ptr_to_compare_rx);    //str_rx-строка в ОЗУ,где лежат
                                                                         //принятые данные от модема                              
                                       }                                
Где-то в коде:
if(COMPARE_STRING_RX(ptr_to_compare_rx=STRING_COMPARE[3]))// что-то делаем если cтрока совпала
else                         //делаем что-то другое-строка не совпала

это для CVAVR.
chief_olimp
в вашем случае насколько я понял сравниваются строки полностью. Я же во всем буффере ищу конкретное слово. На деле у меня это работает так. Копирую данные из флеш в буффер1 и ищу последовательность в буффере2. Но для этого приходится использовать две функции
кстати я уже получил ответ на свой вопрос. может кому пригодится. Все оказалось как всегда просто
Код
const unsigned char PROGMEM blabla[] = "blablabla";

void find (const unsigned char *findbuff){
    unsigned int i=0;
    unsigned char temp;
    while(1){
        temp = pgm_read_byte(findbuff++);
        if(temp==0) break;
        USART0_OutBuf[i++] = temp;
    }
}
int main (void){
    find (blabla);
}
demiurg_spb
Цитата(rezident @ Dec 24 2008, 19:27) *
Во-первых, строка должна заканчиваться завершающим нулем.
Код
unsigned char PROGMEM blabla[] = "blablabla\0";

А во-вторых, перед выводом нужно указателю присвоить значение ее адреса, явно сделав преобразование типа.
Код
findbuff=(unsigned char *)&blabla[0];
Ни во-первых ни во-вторых делать не надо.
Все СИ строки имеют завершающий ноль по определению.
Имя одномерного масссива также является указателем на его первый элемент, так зачем же плодить промежуточные переменные.
Приводить тип не надо, а надо использовать тип char для строк и char* для аргумента функции (ну или const char как в данном случае).
На мой взгляд unsigned char следует использовать только как альтернативу uint8_t, а элементы строк, т.е. буквы-символы в подавляющем большинстве имеют тип char, на то он и нужен.
_Pasha
Код
#define Str const unsigned char PROGMEM
Str blabla[] = "blablabla";
Str bububu[] = "bububu(b)";
Str *all_strings[3]={&blabla, &bububu,NULL};

unsigned char find (const unsigned char *findbuff){
    unsigned int i=0;
    unsigned char temp;
    unsigned char *pos=&USART0_OutBuf[0];
    while(i < sizeof(USART0_OutBuf))
    {
        temp = pgm_read_byte(findbuff++);
        if(temp==0) return 1; // found the full string substitution
        if(*pos++ != temp) break;
        i++;
    }
  return(0);// not found
}

Так, что ли ?
rokhan
2chief_olimp : простите. но то что вы написали - это не find ... это strcpy() причем в извращенной форме.
при чем тут find? если он ничего не возвращет и не сообщает?

2pasha: а если строка не с начала? smile.gif
demiurg_spb
Цитата(_Pasha @ Dec 24 2008, 21:24) *
Код
#define Str const unsigned char PROGMEM
Str blabla[] = "blablabla";
Str bububu[] = "bububu(b)";
Str *all_strings[3]={&blabla, &bububu,NULL};

unsigned char find (const unsigned char *findbuff){
    unsigned int i=0;
    unsigned char temp;
    unsigned char *pos=&USART0_OutBuf[0];
    while(i < sizeof(USART0_OutBuf))
    {
        temp = pgm_read_byte(findbuff++);
        if(temp==0) return 1; // found the full string substitution
        if(*pos++ != temp) break;
        i++;
    }
  return(0);// not found
}

Так, что ли ?

Похоже что не так.
Код
Str *all_strings[3]={blabla, bububu,NULL};
или
Str *all_strings[3]={&blabla[0], &bububu[0],NULL};
_Pasha
Цитата(demiurg_spb @ Dec 24 2008, 22:31) *
Похоже что не так.

Точно! (AVR-libc в помощь). спасибо.

Цитата(rokhan @ Dec 24 2008, 22:28) *
2pasha: а если строка не с начала? smile.gif

тогда считать кол-во совпавших символов и принимать решение исходя из этого.
rezident
Цитата(demiurg_spb @ Dec 24 2008, 23:21) *
Ни во-первых ни во-вторых делать не надо.
Все СИ строки имеют завершающий ноль по определению.
Имя одномерного масссива также является указателем на его первый элемент, так зачем же плодить промежуточные переменные.
Приводить тип не надо, а надо использовать тип char для строк и char* для аргумента функции (ну или const char как в данном случае).
На мой взгляд unsigned char следует использовать только как альтернативу uint8_t, а элементы строк, т.е. буквы-символы в подавляющем большинстве имеют тип char, на то он и нужен.
Теоретически вы правы. На практике могут проявиться нюансы. Как-то, приведение типа указателя без операции извлечения адреса не работает. А приведение типа в данном случае необходимо, т.к. указатель и массив имеют разный тип. IAR, например, сругался бы без приведения типа. Насчет char и unsigned char нужно опять же смотреть опции компилятора. Либо твердо помнить, что в строковых переменных используем только KOI-7 и/или только латиницу.
WHALE
Цитата(chief_olimp @ Dec 24 2008, 20:43) *
в вашем случае насколько я понял сравниваются строки полностью. Я же во всем буффере ищу конкретное слово.

ничего подобного-ищется конкретная лексема в строке.вы,имхо,делаете лишнюю работу,причем 2 раза.
1-зачем-то копируете лексему для поиска из флеш в озу.Нафига?
2-зачем вообще изобретать велосипед-все придумано до нас(с)-стандартная библиотека функций Си.
Почитайте про функцию strstr из стандартной библиотеки,файл string.h.Единственно,вам нужен вам нужен вариант для нахождения в строке,лежащей в озу подстроки,находящейся во флеш.Покурите на эту тему хэлп вашего компилятора.
chief_olimp
Цитата(rokhan @ Dec 24 2008, 22:28) *
2chief_olimp : простите. но то что вы написали - это не find ... это strcpy() причем в извращенной форме.
при чем тут find? если он ничего не возвращет и не сообщает?

Абсолютно согласен. Проблема была не в том что бы написать find. А в том что бы это в тексте выглядело например так
Код
find (text_clcc);

где
Код
PROGMEM char text_clcc[] = "clcc";

Вот весь код процедуры. Ищет конкретное значение произвольной длины в массиве. Возвращает findOK значение "true".
Код
//процедура поиска слова в буффере
void find (const void *findbuff)
{
    findOK = false;
    unsigned int i=0;
    unsigned char temp,j=0;  
    while(1)
    {
        temp = pgm_read_byte(findbuff++);
        if(temp==0) break;
        FIND[i++] = temp;
    }    
    i=0;
    while (i != USART0_InBufSize)
    {
    if (USART0_InBuf[i] == FIND[j])
         {
            i++;j++;findOK = true;
            if (FIND[j] == 0x00) break;
        }
        else
        {
            i++;
            if (findOK == true)
            {
                j=0; i--;
                findOK = false;
            }
        }
    }
}

За подсказку про strstr спасибо. Она кстати тоже работает с ОЗУ. И еще мне нужно будет запоминать позицию конца найденого слова для дальнейшей обработки. С strstr не понятно как это сделать. К тому же неизвесно насколько лучше эта функция работает.
Если кто что подскажет как оптимальнее сделать буду признателен.
rokhan
Я просто в шоке.

думаю мои и быстрее и веселее

Цитата
#define bool int //в зависимости от системы char|word|int|long|int64
/* если нет strlen и memcmp
inline int strlen(char* ins)
{
int i=0;
while(ins[i++]);
return i;
}

inline int memcmp(char* in1,char* in2,int cc)
{
int i=0;
while(cc--)
{
if(in1[cc]!=in2[cc])
return -1;
};

return 0;
}
*/

bool find(char* inb)
{
bool retval=-1;
char inc=*inb;
int i=0;
int slen=strlen(inb);
int pp=USART0_InBufSize-slen;

while(i<pp)
{
if(USART0_InBuf[i]==inc)
if(memcmp(&USART0_InBuf[i],inb,slen)==0)
{
retval=i;
break;
}
i++;
}
return retval;
}


в вашем случае - при использовании глобальных переменных - меняется

Цитата
void find(char* inb)
{
fndOK=-1;
char inc=*inb;
int i=0;
int slen=strlen(inb);
int pp=USART0_InBufSize-slen;

while(i<pp)
{
if(USART0_InBuf[i]==inc)
if(memcmp(&USART0_InBuf[i],inb,slen)==0)
{
fndOK=i;
break;
}
i++;
}
}



блин как тут пробелов наставить?
zltigo
Цитата(rokhan @ Dec 25 2008, 11:23) *
думаю мои и быстрее
...
#define bool int //в зависимости от системы char|word|int|long|int64

Ну-ну... при Ваших побайтовых операциях на не 8bit платфмах поминать слово скорость вообще моветон.
Цитата
и веселее

Это неиспользуемая переменная 'i' в memcmp() для веселья добавлена smile.gif?
Цитата
блин как тут пробелов наставить?

Прочитать про тэги.
rokhan
Спасибо вы нашли опечатку.
Код
На счет тегов могли бы просто помочь с сылкой а не заявлением.
chief_olimp
т.е. каждый раз при очередном сравнивании данные считываются в процедуру. Моя же функция последовательно проходит по всему буферу и ищет лишь первый символ. Когда находит то проверяет остальные. Если совпадают то выход, если нет то ищет с начала искомого слова продолжая шагать по буфферу. Может что и можно сделать с помошью библиотечных функций но меня пока не убедили.
Кстати комплилятор ругается на вашу процедуру "warning: passing arg 1 of `find' discards qualifiers from pointer target type"
zltigo
Цитата(rokhan @ Dec 25 2008, 12:00) *
У автора - используется двойное копирование + двойная проверка...

А я про Вас sad.gif - просто среагировал на рекламный сологан "быстрее и веселее" и не найдя на мой взгляд ни того ни другого (совершенно обычно все) написал ремарку. Добавлю еще, что по нынешним временам библиотечные функции отличаются оптимизированностью (и ASM там не редкое явление)и "сделать" их просто так "в лоб" не получится, если только не за счет наложения дополнительных
ограничений.
Цитата(chief_olimp @ Dec 25 2008, 12:15) *
Может что и можно сделать с помошью библиотечных функций но меня пока не убедили.

А зачем Вас кому-то убеждать smile.gif? Могу сказать одно (глядя на написанное Вами), что современные библиотечные функции написаны много-мнго более оптимально и Вам следует, как минимум, для начала воспользоваться ими.
Например, та memcmp(), которой я пользовался для ARM лет пять тому назад, до тех пор, пока IAR не "сделал" и ее выпустив очередную свою версию библиотеки.
CODE

//---------------------------------------------------------------------------
// memcmp()
// compare unsigned char s1[n], s2[n]
// int (memcmp)(const void *s1, const void *s2, size_t n)
//---------------------------------------------------------------------------
RSEG CODE:CODE:NOROOT(2)
ARM

memcmp:
mov r3,r0 // Copy 1st arg, p1
mov r0,#0 // Set return value = 0
teq r2,#0 // Is n == 0 ?
bxeq lr // Return if n == 0

stmdb sp!,{r4-r6,lr} // Save registers on stack

cmp r2,#12 // Is n > 12 */
ble ByteLoop // If n <= 12, jump

sub r0,r3,r1 // p1 - p2
ands r0,r0,#3 // (p1 - p2) & 3
beq WordCompare // Jump if byte offsets match

// The strings begin at different byte offsets WRT word boundaries.
// Loop below processes only a single pair of bytes per iteration.
ByteLoop:
ldrb r0,[r3],#1 // b1 = next byte from string 1
ldrb r4,[r1],#1 // b2 = next byte from string 2
subs r0,r0,r4 // b1 - b2
bne ByteBreak // if b1 != b2, break out of loop
subs r2,r2,#1 // --n (decrement loop counter)
bne ByteLoop // Loop again if n > 0

ByteBreak:
TheEnd:
ldmia sp!,{r4-r6,lr} // Return
bx lr


// The two strings have same starting byte alignment WRT word boundary.
// Set up inner loop that compares a pair of words per iteration.

WordCompare:
add r5,r3,r2 // e1 = p1 + n (point to trailing byte)
and lr,r3,#3 // align = p1 & 3 (initial byte offset)
bic r3,r3,#3 // p1 &= ~3 (point to word boundary)
bic r1,r1,#3 // p2 &= ~3
add r2,r5,#3 // e1 + 3
sub r2,r2,r3 // e1 + 3 - p1
mov r2,r2,lsr #2 // N Words = (e1 + 3 - p1) >> 2

mvn r6,#0 // Initialize mask to all 1s
mov r0,lr,lsl #3 // Convert byte offset to bit offset
mov r6,r6,lsl r0 // Poke holes in mask for invalid bytes
ldr r0,[r3],#4 // w1 = *p1++
and r0,r0,r6 // Isolate starting bytes in 1st string
ldr r4,[r1],#4 // w2 = *p2++
and r4,r4,r6 // Isolate starting bytes in 2nd string


// Inner loop:
// Compare the two strings one word at a time to look for a mismatch.
// If the two strings match, return 0.
WordLoop:
subs r0,r0,r4 // w1 - w2
bne WordBreak // if w1 != w2, break out of loop
ldr r0,[r3],#4 // w1 = *p1++
subs r2,r2,#1 // --nWords
ldr r4,[r1],#4 // w2 = *p2++
bne WordLoop // Loop again if more words in string
mov r0,#0 // Set return argument = 0
b TheEnd // All done. Return


// The strings may still match if the apparent mismatch happened in
// the final pair of words from the two strings (in trailing bytes).
WordBreak:
teq r2,#1 // N Words == 1? (mismatch at EOS?)
bne FindMismatch // Jump if nWords != 1

ands r5,r5,#3 // Is trailing byte word-aligned?
beq FindMismatch // Jump if word-aligned (real mismatch)

mvn r6,#0 // Initialize mask to all 1s
mov r5,r5,lsl #3 // Convert byte offset to bit offset
mvn r6,r6,lsl r5 // Poke holes in mask for invalid bytes
ands r0,r0,r6 // Mask off trailing bytes, string 1
beq TheEnd // If w1 == w2, return val = 0


// We detected a mismatch in the current pair of words from the strings.
// But in which byte position within the words did the mismatch occur?
FindMismatch:
add r3,r0,r4 // Restore value w1

NextByte:
and r0,r3,#0xff // b1 = w1 & 0xff (isolate byte)
and r2,r4,#0xff // b2 = w2 & 0xff
subs r0,r0,r2 // Return val = b1 - b2 ?

bne TheEnd // If val != 0 - Return

mov r3,r3,lsr #8 // w1 >>= 8 (position next byte)
mov r4,r4,lsr #8 // w2 >>= 8
b NextByte // If b1 != b2, loop again
demiurg_spb
Цитата(rezident @ Dec 24 2008, 22:49) *
Теоретически вы правы. На практике могут проявиться нюансы. Как-то, приведение типа указателя без операции извлечения адреса не работает. А приведение типа в данном случае необходимо, т.к. указатель и массив имеют разный тип. IAR, например, сругался бы без приведения типа. Насчет char и unsigned char нужно опять же смотреть опции компилятора. Либо твердо помнить, что в строковых переменных используем только KOI-7 и/или только латиницу.
Я хочу сказать, что при грамотном проектировании программы приводить типы проактически не требуется - это загромождает программу. У автора ошибка в проектировании он почему-то решил применять разные типы данных для сущности и передачи указателя в функцию на эту сущность. Мне это совершенно не ясно. И это при том, что сущность едина в "двух лицах" - это строка типа чар. Вся таблица ascii прекрасно ложится в тип чар (это минимум 8 бит в нынешнем понимании, а иногда и немного больше) и пусть этот чар будет хоть со знаком, хот без - это может варьироваться от системы или опций компилятора. Повторюсь ещё раз строки должны состоять из обычных чаров - всё остальное от лукавогоsmile.gif Вот мой аргумент:
Код
const char slovo[] = "slovo";
if (slovo[0]=='s')
{
}
Видите тип 's' - это char (я така понимаю). Поэтому я правомерно могу писать такой код. Комар носа не подточит.
Ну а если ваш компилятор ругается на строки с символами код которых боьше 127 (gcc не ругается, bc и msvc тоже), то надо просто покопаться в опциях компилятора.
HARMHARM
Цитата(demiurg_spb @ Dec 25 2008, 12:24) *
Ну а если ваш компилятор ругается на строки с символами код которых боьше 127 (gcc не ругается, bc и msvc тоже), то надо просто покопаться в опциях компилятора.

Большинство компиляторов (все, что я видел до сих пор) имеют char по умолчанию unsigned. Но именно потому, что он переключается, char, unsigned char и signed char разные типы. Полное право имеет ругаться.
alx2
Цитата(rezident @ Dec 25 2008, 00:49) *
Теоретически вы правы. На практике могут проявиться нюансы. Как-то, приведение типа указателя без операции извлечения адреса не работает.
Я не совсем понял. Под расхождением теории и приктики подразумевается несоответствие поведениея компилятора спецификации языка? Тогда не лучше ли сменить компилятор, чем подгонять программу под его баги? Если же я понял неправильно, хочется увидеть пример, где при наличии unsigned char blabla[] требуется писать (unsigned char *)blabla.
zltigo
Цитата(HARMHARM @ Dec 25 2008, 14:14) *
Большинство компиляторов (все, что я видел до сих пор) имеют char по умолчанию unsigned.

Жутко "повезло", ибо по жизни издревле принято (хотя и отдано на откуп компилятору/платформе) с точностью до наоборот signed и это пожалуй, правильно (или просто больше привык smile.gif ). То, что Вы встречали, очевидно, уже сложилось под влиянием узкозаточенности под чего-нибудь embedded на платформах 8bit или наоборот жестких 32битовиках типа ARM. На той-же x86, если увижу unsigned char по умолчанию, очень даже поплююсь на такой компилятор.
chief_olimp
Код
void find(char* inb)
{
fndOK=-1;
char inc=*inb;
int i=0;
int slen=strlen(inb);
int pp=USART0_InBufSize-slen;

while(i<pp)
{
if(USART0_InBuf[i]==inc)
if(memcmp(&USART0_InBuf[i],inb,slen)==0)
{
fndOK=i;
break;
}
i++;
}
}


ну не работает у меня этот код с строкой в программе типа
Код
find (text_clcc);
где
Код
PROGMEM char text_clcc[] = "clcc";

И еще не смотря на компактность написания мой код на две строчки длинее всего.
Может автор сможет лучше с моим кодом сравнить по объему и быстродействию. Буду очень признателен. Сам я с асма только перелез и это моя первая программа на си. Поэтому и функциями библиотечными мало пользуюсть так как мало о них знаю.
Сергей Борщ
Цитата(chief_olimp @ Dec 25 2008, 13:44) *
Сам я с асма только перелез и это моя первая программа на си. Поэтому и функциями библиотечными мало пользуюсть так как мало о них знаю.
Ну так и надо начать программирование с изучения документации. С чтения WinAVR/doc/avr-libc/FAQ.htm и остальной документации в этой папке. Хотя бы тех разделов, в которых поиск находит слово PROGMEM.
Если вы писали на асме, то должны четко представлять, что для обращения к данным в озу используются команды LD, LDD, LDS, а для чтения из программной памяти - LPM. И должны понимать, что компилятор не может только по значению обычного указателя понимать, какую команду использовать. Иными словами, функции strlen(), memcmp() не могут работать и со строками в ОЗУ и со строками во флеше. Чтобы обойти эту нестыковку стандарта языка С и процессоров с несколькими адресными пространствами придуманы аналоги этих функций для работы с флеш. Еще в ответе №4 Tiro вам подсказал, где вы можете найти ответ. Вы не читаете ответов или не хотите следовать данным в них советам? Вы не хотите прочитать документацию? Тогда неудивительно, что код не работает и "так мало о них знаю".
Код
void find(prog_char const * inb)
{
    prog_char const * found = strstr_P(USART0_InBuf, inb);
    if (!found)
        fndOK=-1;
    else
        fndOK = found - USART0_InBuf;
}
demiurg_spb
Цитата(HARMHARM @ Dec 25 2008, 14:14) *
Большинство компиляторов (все, что я видел до сих пор) имеют char по умолчанию unsigned. Но именно потому, что он переключается, char, unsigned char и signed char разные типы.
Примеры компиляторов? Это небось только узкоспециализированные и заточенные под мало разрядные MCU. Я солидарен с zltigo и в основном всегда char знаковый. Проведите аналогию с int.
chief_olimp
Документацию я как раз читаю. Только напоминаю я на си пишу месяц с лишним. Скажите у Вас у самого код что сверху работает со словами из FLASH? Мой код у меня работает и меня лично вполне устаивает. Здесь же вместо того что бы подсказать посылают по ссылкам которые я уже читал и эти знания успешно применяю в других кусках программы. Код что выше у меня не работает, и выдает ошибку что не понимает аттрибута функции.
rezident
Цитата(demiurg_spb @ Dec 25 2008, 15:24) *
Я хочу сказать, что при грамотном проектировании программы приводить типы проактически не требуется - это загромождает программу.
Я с вами согласен, что нужно писать так, чтобы типы приводить не приходилось. Но я-то писал в применении к конкретному коду, а не к коду "вообще" или "в принципе".
Цитата(demiurg_spb @ Dec 25 2008, 15:24) *
Вот мой аргумент:
Код
const char slovo[] = "slovo";
if (slovo[0]=='s')
{
}
Видите тип 's' - это char (я така понимаю). Поэтому я правомерно могу писать такой код. Комар носа не подточит.
Именно тут - да, можете. А что произойдет в случае сравнения на больше/меньше? Тоже будете уповать на то, что по-умолчанию char как unsigned char используется?
Цитата(demiurg_spb @ Dec 25 2008, 15:24) *
Ну а если ваш компилятор ругается на строки с символами код которых боьше 127 (gcc не ругается, bc и msvc тоже), то надо просто покопаться в опциях компилятора.
Ага! Так все-таки "стоит покопаться в опциях" wink.gif
HARMHARM
Цитата(demiurg_spb @ Dec 25 2008, 14:11) *
Примеры компиляторов? Это небось только узкоспециализированные и заточенные под мало разрядные MCU. Я солидарен с zltigo и в основном всегда char знаковый. Проведите аналогию с int.
Да, полностью согласен с Вами и Zltigo. Это мое воинствующее невежество выстрелило sad.gif
Чтобы закрыть тему с char приведу цитату из описания на gcc:
Цитата
Each kind of machine has a default for what `char' should be. It
is either like `unsigned char' by default or like `signed char' by
default.

Ideally, a portable program should always use `signed char' or
`unsigned char' when it depends on the signedness of an object.
But many programs have been written to use plain `char' and expect
it to be signed, or expect it to be unsigned, depending on the
machines they were written for. This option, and its inverse, let
you make such a program work with the opposite default.

The type `char' is always a distinct type from each of `signed
char' or `unsigned char', even though its behavior is always just
like one of those two.
demiurg_spb
Цитата(rezident @ Dec 25 2008, 15:35) *
Я с вами согласен, что нужно писать так, чтобы типы приводить не приходилось. Но я-то писал в применении к конкретному коду, а не к коду "вообще" или "в принципе".
Именно тут - да, можете. А что произойдет в случае сравнения на больше/меньше? Тоже будете уповать на то, что по-умолчанию char как unsigned char используется?

Я уповать не буду. Мне вообще всё равно что за тип char (со знаком или без) и всем остальным это должно быть тоже безразлично. Ибо его надо использовать только для работы с текстовыми строками и символами. Я легко и непринуждённо буду писать
Код
char ch = '0'; .... ch++; ... if ((ch>='0')&&(ch<='9')) {}
и даже не вспомню о надуманной проблеме знака. Все прекрасно будет работать и именно так как я хочу.
В развитие темы хочу добавить, что когда я вижу код
Код
for (char i=0; i<N; i++)  {} // так писать нельзя
я никак не могу избавится от желания отшлёпать автора такого кода. Лень написать unsigned char так используйте тип uint8_t.
Код
#include <stdint.h>
for (uint8_t i=0; i<N; i++)  {}
Но осознанно создавать неопределённое поведение программы - это по меньшей мере неблагоразумно.
Сергей Борщ
Цитата(chief_olimp @ Dec 25 2008, 14:18) *
Скажите у Вас у самого код что сверху работает со словами из FLASH?
Конкретно этот не проверял, но если в pgmspace.h описан прототип extern char *strstr_P(const char *, PGM_P); то у меня нет основания сомневаться в том, что первый агрумент - указатель на строку в ОЗУ, а второй - на строку в flash. Описание стандартной функции strstr гласит:
Цитата
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
А это именно то, что требуется, судя по вашему исходнику.
Цитата(chief_olimp @ Dec 25 2008, 14:18) *
Мой код у меня работает и меня лично вполне устаивает.
Весьма сомнительно - в вашем коде нет обращения к flash.
Цитата(chief_olimp @ Dec 25 2008, 14:18) *
Код что выше у меня не работает, и выдает ошибку что не понимает аттрибута функции.
Тренировки в телепатии, безусловно, полезны. Но пока мы не достигли совершенства в этой области неплохо было бы приводить конкретную строку, на которую выдается ошибка и конкретный текст ошибки. Мой код прекрасно компилируется:
CODE
main.cpp:
#include <avr\pgmspace.h>
char USART0_InBuf[10];
int fndOK;
void find(prog_char const * inb)
{
prog_char const * found = strstr_P(USART0_InBuf, inb);
if (!found)
fndOK=-1;
else
fndOK = found - USART0_InBuf;
}

main.lst:
531 .section .text._Z4findPKc,"ax",@progbits
532 .global _Z4findPKc
534 _Z4findPKc:
535 .LFB37:
536 .LSM79:
537 /* prologue: frame size=0 */
538 /* prologue end (size=0) */
539 .LVL13:
540 .LBB23:
541 .LSM80:
542 0000 BC01 movw r22,r24 ; inb, inb
543 0002 80E0 ldi r24,lo8(USART0_InBuf) ; ,
544 0004 90E0 ldi r25,hi8(USART0_InBuf) ; ,
545 .LVL14:
546 0006 00D0 rcall strstr_P ;
547 .LVL15:
548 .LSM81:
549 0008 0097 sbiw r24,0 ; found
550 .LVL16:
551 000a 01F4 brne .L64 ; ,
552 .LSM82:
553 000c 8FEF ldi r24,lo8(-1) ; tmp45,
554 000e 9FEF ldi r25,hi8(-1) ; tmp45,
555 .LVL17:
556 0010 00C0 rjmp .L68 ;
557 .LVL18:
558 .L64:
559 .LSM83:
560 0012 8050 subi r24,lo8(USART0_InBuf) ; found,
561 0014 9040 sbci r25,hi8(USART0_InBuf) ; found,
562 .L68:
563 0016 9093 0000 sts (fndOK)+1,r25 ; fndOK, found
564 001a 8093 0000 sts fndOK,r24 ; fndOK, found
565 001e 0895 ret
566 .LBE23:
567 /* epilogue: frame size=0 */
568 /* epilogue: noreturn */
569 /* epilogue end (size=0) */
570 /* function void find(const prog_char*) size 16 (16) */
chief_olimp
Обращение есть.
CODE
void find (const void *findbuff)
{
findOK = false;
unsigned int i=0;
unsigned char temp,j=0;
pointer = 0;
while(1)
{
temp = pgm_read_byte(findbuff++);
if(temp==0) break;
FIND[i++] = temp;
}
i=0;
while (i != USART0_InBufSize)
{
if (USART0_InBuf[i] == FIND[j])
{
i++;j++;findOK = true;
if (FIND[j] == 0x00)
{
pointer = i;
break;
}
}
else
{
i++;
if (findOK == true)
{
i = i-j; j=0;
findOK = false;
}
}
}
}

Но перед вами снимаю шляпу. Три страницы нужно было исписать что бы прийти к трем строчкам текста
zltigo
Цитата(demiurg_spb @ Dec 25 2008, 16:37) *
Я легко и непринуждённо буду писать...

И это правильно. Почти всегда правильно sad.gif без кирилицы...
Цитата
В развитие темы хочу добавить, что когда я вижу код
Код
for (char i=0; i<N; i++)  {} // так писать нельзя
я никак не могу избавится от желания отшлёпать автора такого кода. Лень написать unsigned char так используйте тип uint8_t.
Код
#include <stdint.h>
for (uint8_t i=0; i<N; i++)  {}

И за то, что Вы написали, надо больно шлепать, если это перенести не на восьмибитовик smile.gif. Исправитесь?
rezident
Цитата(demiurg_spb @ Dec 25 2008, 18:37) *
и даже не вспомню о надуманной проблеме знака. Все прекрасно будет работать и именно так как я хочу.
Будет работать до тех пор, пока вы используете только первую половину ASCII или KOI-7 и не используете в строковых переменных кириллицу. О чем я выше уже упомянул.
Цитата(demiurg_spb @ Dec 25 2008, 18:37) *
Лень написать unsigned char так используйте тип uint8_t.
Вообще-то в качестве автоматических переменных цикла принято использовать тип int или unsigned int. А типы uint8_t, uint16_t и прочие подобные им не являются полностью стандартными, т.к. появились лишь как расширение в C99 и отсутствовали в ANSI C (хотя здесь могу и ошибаться, т.к. я не слишком большой знаток истории развития языка Си).
demiurg_spb
Цитата(rezident @ Dec 25 2008, 18:00) *
Будет работать до тех пор, пока вы используете только первую половину ASCII или KOI-7 и не используете в строковых переменных кириллицу. О чем я выше уже упомянул.
Вообще-то в качестве автоматических переменных цикла принято использовать тип int или unsigned int. А типы uint8_t, uint16_t и прочие подобные им не являются полностью стандартными, т.к. появились лишь как расширение в C99 и отсутствовали в ANSI C (хотя здесь могу и ошибаться, т.к. я не слишком большой знаток истории развития языка Си).


Это программа для AVR и тут int не то чтобы сильно подходит.

Я использую не только первую половину ASCII...
Код
//=============================================================================
unsigned char is_rus_word(const char* str)
{
    char ch;    
    while ( (ch=*str++) )
    {
        if ((ch<'А')||(ch>'я'))
        {
            return 0;
        }
    }    
    return 1;
}
//=============================================================================
int main(void)
{
    const char buratino[] = "Буратино";    
    is_rus_word(buratino);
    return (0);
}


avr-gcc -c -mmcu=atmega64 -I. -gdwarf-2 -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes....

Код
00003a2a <is_rus_word>:
3a2a:  fc 01  movw r30, r24
3a2c:  04 c0  rjmp    .+8
3a2e:  80 3c  cpi    r24, 0xC0
3a30:  10 f4  brcc    .+4
3a32:  80 e0  ldi    r24, 0x00
3a34:  08 95  ret
3a36:  81 91  ld    r24, Z+
3a38:  88 23  and    r24, r24
3a3a:  c9 f7  brne    .-14
3a3c:  81 e0  ldi    r24, 0x01
3a3e:  08 95  ret
zltigo
Цитата(demiurg_spb @ Dec 25 2008, 19:38) *
avr-gcc -c -mmcu=atmega64 -I. -gdwarf-2 -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes....

И указание -funsigned-сhar компилятору теперь назывется
Цитата
Мне вообще всё равно что за тип char (со знаком или без) и всем остальным это должно быть тоже безразлично.

Если "безразлично" то поставьте уж signed smile.gif.
demiurg_spb
Цитата(zltigo @ Dec 25 2008, 17:31) *
И за то, что Вы написали, надо больно шлепать, если это перенести не на восьмибитовик smile.gif. Исправитесь?
Нет я пишу для AVR всегда только такsmile.gif Ну для x86 естественно использую родной int.

avr-gcc -c -mmcu=atmega64 -I. -gdwarf-2 -DF_CPU=14745600UL -Os -fsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes....
Код
    3a2a:    fc 01           movw    r30, r24
    3a2c:    05 c0           rjmp    .+10
    3a2e:    80 5c           subi    r24, 0xC0; 192
    3a30:    80 34           cpi    r24, 0x40; 64
    3a32:    10 f0           brcs    .+4
    3a34:    80 e0           ldi    r24, 0x00
    3a36:    08 95           ret
    3a38:    81 91           ld    r24, Z+
    3a3a:    88 23           and    r24, r24
    3a3c:    c1 f7           brne    .-16
    3a3e:    81 e0           ldi    r24, 0x01
    3a40:    08 95           ret
Аналогичный результат если ничего не задавать ни fsigned-char ни funsigned-char, т.е. по умолчанию signed...
Исправим формулировку: мне уже не всё равно какой тип у char, т.к. через makefile он принудительно выбран как без знака.
Генри Форд: "Форд может быть любого цвета если он чёрный" звучит примерно такsmile.gif
Прошу заметить, что даже так программа будет работать правильно!
zltigo
Цитата(demiurg_spb @ Dec 25 2008, 19:38) *
Это программа для AVR и тут int не то чтобы сильно подходит.

Само собой smile.gif. Посему подыщите в <stdint.h> более подходящий тип. Хотя sad.gif, по личному опыту бывают варианты, посему спокойнее использовать "свой" у меня он bint - "базовый int" не менее чем байт.
demiurg_spb
Цитата(zltigo @ Dec 25 2008, 19:54) *
Само собой smile.gif. Посему подыщите в <stdint.h> более подходящий тип. Хотя sad.gif, по личному опыту бывают варианты, посему спокойнее использовать "свой" у меня он bint - "базовый int" не менее чем байт.

На что Вы намекаете?smile.gif
В <stdint.h> я не смог найти ничего более подходящего для AVR чем uint8_t.
Для AVR Ваш bint = unsigned char? Или Вы уже совсем их (AVR) не используете по понятным причинам...
zltigo
Цитата(demiurg_spb @ Dec 25 2008, 20:27) *
На что Вы намекаете?smile.gif
В <stdint.h> я не смог найти ничего более подходящего для AVR чем uint8_t.

Естественно на uint_least8_t и/или uint_fast8_t при этом речь я вел о подходящем вообще для портирования кода, а не подходящим только к AVR
Цитата
Для AVR Ваш bint = unsigned char?

Да для всех восьмибитоваков unsigned char. Для все остальных int
Цитата
Или Вы уже совсем их (AVR) не используете по понятным причинам...

Использую smile.gif иначе у меня просто не было-бы bint за полной его ненадобностью на 16/32/64 платформах.
demiurg_spb
Цитата(zltigo @ Dec 25 2008, 20:34) *
Естественно на uint_least8_t и/или uint_fast8_t при этом речь я вел о подходящем вообще для портирования кода, а не подходящим только к AVR
Спасибо!
Но хочется всё-таки узнать, когда же есть хоть малейший вред в случае char со знаком.
Я так и не смог выдумать такого...
И мне что-то подсказывает, что это таки надуманная проблема...
alx2
Цитата(Сергей Борщ @ Dec 25 2008, 17:05) *
И должны понимать, что компилятор не может только по значению обычного указателя понимать, какую команду использовать. Иными словами, функции strlen(), memcmp() не могут работать и со строками в ОЗУ и со строками во флеше.
Во времена MCS-51, тоже имеющего много разных адресных пространств, компиляторы использовали "универсальные" трехбайтные указатели, в которых первый байт был селектором адресного пространства. Соответственно, и функции, принимавшие такие указатели, вполне успешно работали со строками хоть в памяти данных, хоть в памяти программ. И как раз для начинающих это понятно и удобно, ибо соответствует правилам языка. Продвинутые кодеры могли использовать нестандартные спецификаторы, если тредовалось уменьшить оверхед и/или размер указателей...
zltigo
Цитата(demiurg_spb @ Dec 25 2008, 20:43) *
Но хочется всё-таки узнать, когда же есть хоть малейший вред в случае char со знаком.

Не понимаю вопроса sad.gif Поскольку есть разница и отнюдь не "малейшая" между знаковыми и беззнаковыми представлениями чисел, то и "вред" от необдуманной замены одного другим может быть отнюдь не "малейшим". Вам ведь не все равно будет если компилятор посчитает число которое Вы полагаете равным 128 меньшим чем, например, число 1.
Сергей Борщ
Цитата(alx2 @ Dec 26 2008, 12:36) *
Во времена MCS-51, тоже имеющего много разных адресных пространств, компиляторы использовали "универсальные" трехбайтные указатели, в которых первый байт был селектором адресного пространства.
Вот именно: кроме собственно адреса такой указатель содержит искусственно введенную дополнительную информацию. По одному только адресу ("чистому" указателю) определить, к какому адресному пространству нужно обращаться, невозможно.
Сергей Борщ
Цитата(Сергей Борщ @ Dec 26 2008, 17:32) *
такой указатель содержит искусственно введенную дополнительную информацию.
Подумал и уточню: искуственно введенную информацию на этапе исполнения. В случае использования дублирующих функций для доступа к другим адресным пространствам имена (=адреса вызова) этих функций также будут дополнительной информацией, но уже на этапе компиляции. Как и специальные квалификаторы вроде __flash. За исключением очень редких случаев предпочтительнее использование информации этапа компиляции, т.к. это дает более оптимальный как по времени исполнения, так и по размеру, код.
P.S. для разрешения на этапе исполнения iar тоже имеет специально обучнный квалификатор указателей generic. avr-gcc не имеет встроенной в компилятор поддержки различных адресных пространств, только через макросы библиотеки avr-libc.
demiurg_spb
Цитата(zltigo @ Dec 26 2008, 16:54) *
Не понимаю вопроса sad.gif Поскольку есть разница и отнюдь не "малейшая" между знаковыми и беззнаковыми представлениями чисел, то и "вред" от необдуманной замены одного другим может быть отнюдь не "малейшим". Вам ведь не все равно будет если компилятор посчитает число которое Вы полагаете равным 128 меньшим чем, например, число 1.
Это мне прекрасно понятно. Я уточню вопрос. Тут кто-то говорил что будут проблемы с русской кодировкой или что-то в этом духе. Так вот я немогу понять где эти проблемы? Я не говорю о типе char как о типе данных для представления чисел (с этим всё кристально ясно), я говорю лишь о строках и символах. При работе с буковками я никогда не думаю об их "цифровом коде" - это вредно для мозгаsmile.gif, я думаю лишь об их взаимном расположении в кодовой таблице.
Ведь ряд чисел для типа char со знаком получается такой: 0,1,...126,127,-128,-127,...-2,-1
И даже если я попытаюсь сравнить символ на попадание в диапазон, границы которого лежат в левой и правой половинках ряда, то всё будет хорошо. Псевдокод: if (ch>126)&&(ch<-127) {} - это полностью соответствует if (ch>126)&&(ch<129) {} в случае когда char без знака. И если в этих выражения стоят не конкретные числа, а как я уже говорил у меня там _всегда_ что то типа 'А' и 'Я' - то всё будет хорошоwink.gif А меня пытаются убеждать в обратном, но я не сдаюсь.
Сергей Борщ
Цитата(demiurg_spb @ Dec 27 2008, 12:03) *
И если в этих выражения стоят не конкретные числа, а как я уже говорил у меня там _всегда_ что то типа 'А' и 'Я' - то всё будет хорошоwink.gif
Код
    uint8_t char_code = static_cast<uint8_t>(c);
    if(char_code < ' ')
        return &Small_Char[0];
    if(char_code < sizeof(Small_Char) / sizeof(Small_Char[0]) + ' ')
        return &Small_Char[char_code - ' '];
    if(char_code < (uint8_t)'А') // cyrilic 'A'
        return &Small_Char[0];
    if(char_code < sizeof(Small_Char_Cyr) / sizeof(Small_Char_Cyr[0]) + (uint8_t)'А')
        return &Small_Char_Cyr[char_code - 'А'];
    return &Small_Char[0];   //unreacheable, cyrilic charset ends at '\xFF'
если char знаковый, то if(char_code < 'А') /* cyrilic 'A' */ работает с точностью до наоборот от ожидаемого.
rezident
Цитата(demiurg_spb @ Dec 27 2008, 15:03) *
Ведь ряд чисел для типа char со знаком получается такой: 0,1,...126,127,-128,-127,...-2,-1
Ошибаетесь. Представление чисел со знаком такое же, как и на числовой оси декартовых координат. -128 слева, 0 в центре и +127 справа. Если мне не верите, то загляните в limits.h.
Код
#define CHAR_MAX         127            /* Maximum "char" value */
#define CHAR_MIN        (-128)          /* Mimimum "char" value */

Цитата(demiurg_spb @ Dec 27 2008, 15:03) *
Псевдокод: if (ch>126)&&(ch<-127) {}
При знаковом char условие невыполнимо, т.к. число не может одновременно быть "больше большего" и "меньше меньшего".
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.