Двойное условие в while

Тема в разделе "WASM.ZEN", создана пользователем cresta, 24 окт 2005.

  1. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Способен ли С++ обрабатывать два условия, связанные в один оператор while или if?

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

    Например так: есть текст, считаный в память по адресу в lpText, строки в котором разделены символами 0xA или 0xD. Надо считать из текста двадцать строк и записать в листбокс. Поиск конца строки идёт по условию:
    Код (Text):
    1. while ((*((char*) ((int)lpText+j))!=0xA) || (*((char*) ((int)lpText+j))!=0xD))



    Код (Text):
    1.  
    2.     char    buffer[256]; //реально строки не длиннее 50-60 символов
    3.     for (int i=0; i<20; i++)
    4.         {
    5.         int j = 0;
    6.         // while не останавливается, buffer переполняется и далее прога вылетает
    7.         while ((*((char*) ((int)lpText+j))!=0xA) || (*((char*) ((int)lpText+j))!=0xD))
    8.             {
    9.             buffer[j] = *((char*) (int)lpText+j);
    10.             j++;
    11.             }
    12.         //до сюда дело не доходит
    13.         DBG_DEC(i);
    14.         buffer[j] = 0;
    15.         lpText += j;
    16.         while (*((char*) ((int)lpText))==0xA || *((char*) ((int)lpText))==0xD)
    17.             lpText++;
    18.        
    19.         SendMessage (hList, LB_ADDSTRING, 0, (LPARAM) buffer);
    20.         }
    21.  
     
  2. Artemy

    Artemy New Member

    Публикаций:
    0
    Регистрация:
    18 май 2005
    Сообщения:
    48
    Адрес:
    Russia
    в логике грабли.
    Код (Text):
    1.  
    2. while ((*((char*) ((int)lpText+j))!=0xA) [b]||[/b] (*((char*) ((int)lpText+j))!=0xD))




    надо
    Код (Text):
    1. while ((*(char*)(lpText+j)!=0xA) [b]&&[/b] (*(char*)(lpText+j)!=0xD))
     
  3. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Почему? Мне надо чтобы вышел из цикла по любому из двух символов, а не на оба сразу. Именно или.

    В тексте может быть 0D0A, 0A0D, 0A, 0D -

    любой из вариантов, поэтому проверяю на любой первый встретившийся символ.
     
  4. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Действительно, тут ведь != стоит. Мда...
     
  5. rgo

    rgo New Member

    Публикаций:
    0
    Регистрация:
    21 мар 2005
    Сообщения:
    87


    если бы ты эту строчку переписал следующим образом:



    while (lpText[j] != 0xA || lpText[j] != 0xD)



    то, мне кажется, ошибку было бы проще найти...

    Ежели lpText объявлен как void*, то можно написать например так:



    static inline char char_at (int idx, void *buf)

    {

    char *str = (char*) buf;

    /*в случае C++ 'char *str = reinterpret_cast<char*> (buf)'*/

    return str[idx];

    }

    ...

    while (char_at (j, lpText) != 0xA || char_at (j, lpText) != 0xD)
     
  6. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    есть текст, считаный в память по адресу в lpText

    Ты отдаешь себе отчет как работает (int)lpText+j?

    У тебя каждый символ занимает четыре байта?
     
  7. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    cresta



    Где ты научился таким извращенным приведениям типов? :))
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    q_q

    Хоть я в сях и профан, но ИМХО (int)lpText+j это просто число равное адресу lpText смещенному на j байт, и уж затем это число\адрес приводится к типу char*. Может и коряво, но вроде верно ;)
     
  9. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    leo

    В Си принято делать так:
    Код (Text):
    1. (type *)lpText + j
    т.к. это позволяет делигировать подсчет числа (зависящего от тип) байт компилятору.
     
  10. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    leo



    Я ж не раз писал про это здесь..
    Код (Text):
    1. (type)var + i == var + i*sizeof(type);
     
  11. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    IceStudent



    (type*)var + i == (char*)var + i*sizeof(type);



    :derisive:
     
  12. SI_16

    SI_16 New Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    10
    так еще лучше:



    (type*)var + i == (type*)((long)var + i*sizeof(type));
     
  13. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    _DEN_

    Хотел вторую часть сделать на асме вообще-то :)
     
  14. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    SI_16



    static_cast<type*>(static_cast<void*>(var + i)) == static_cast<type*>(static_cast<void*>(static_cast<char*>(static_cast<v oid*>(var)) + i * sizeof(type)))



    :))))
     
  15. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Пока меня не было, тут такая дискуссия...



    _DEN_

    Я самоучка. И ни одной книги про си не читал.

    Скажу прямо, может несколько грубо: в гробе я видал этот си с его бесчисленными типами и необходимостью постоянно и непрерывно что-то куда-то приводить. Я б этого страуса с его трупом восемь раз расстрелял бы.



    q_q

    lpText у меня объявлен как LPVOID, т.к. VirtualAlloc возвращает такой тип, если я его объявлю как char*, то тогда в другом месте при выделении памяти придётся приводить тип к char*. В любом случае куда-то да придётся приводить. А в конечном итоге всё равно получился byte ptr, как ни крути, т.к. в конце концов это указатель (char*)

    (int)lpText сделал, чтобы компилятор не ругался на размер LPVOID.
     
  16. YoungBastard

    YoungBastard New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2005
    Сообщения:
    231
    Адрес:
    Russia
    cresta

    а Страуструпа стоило бы почитать, хоть там и про си не очень много написано... и книги по си
     
  17. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    YoungBastard



    Пытался я его почитать, "Преступление и наказание" Достоевского в сравнении с ним - как комиксы :dntknw:



    Вот тогда вопрос к гурам, блещущим знаниями :) Процедура считывает caption нажатой кнопки (которые состоят из букв алфавита: A,B,C,D....Z), и выводит в листбокс все строки файла (считанного в lpRus или lpEng), начинающиеся с этой буквы.

    Сейчас lpText объявил как char*, и убрал (int), хотя и с ним процедура работала корректно.

    Так как же должна выглядеть процедура с точки зрения правильного стиля? О размере кода и его быстродействии речь не идёт. Только правильность стиля.


    Код (Text):
    1.  
    2. void Fill_List(int buttonID)
    3. {
    4.     char    buffer[256];
    5.     char*   lpText;
    6.  
    7.     GetDlgItemText(hWnd, buttonID, buffer, 256);
    8.     cr_strlcase(buffer);                //перевод caption в нижний регистр
    9.     if ( buffer[0] < 0 )                //char не unsigned, => если <0, то старший бит установлен
    10.         lpText = (char*) lpRus;         //значит кириллица
    11.     else
    12.         lpText = (char*) lpEng;
    13.  
    14.     SendMessage (hList, LB_RESETCONTENT, 0, 0);
    15.        
    16.     int i = 2;                          //первую строку не читаем (по тех. причинам)
    17.     //поиск строки, начинающейся с caption
    18.     while (1)
    19.         {
    20.         if ( buffer[0] == *(lpText+i) )
    21.             if ( *(lpText+i-1)==0xA || *(lpText+i-1)==0xD )
    22.                 break;
    23.         i++;
    24.         }
    25.     lpText += i;                        //подравнялись на начало строки
    26.    
    27.     while (1)
    28.         {
    29.         int j = 0;
    30.         //запихиваем символы строки в buffer, пока не встретится 0xD или 0xA
    31.         while ( *(lpText+j)!=0xA && *(lpText+j)!=0xD )
    32.             {
    33.             buffer[j] = *(lpText+j);
    34.             j++;
    35.             }
    36.         //забиваем символ переноса нулём
    37.         buffer[j] = 0;
    38.         lpText += j;
    39.         //подстраиваем указатель на начало следующей строки
    40.         while ( *(lpText)==0xA || *(lpText)==0xD )
    41.             lpText++;
    42.        
    43.         SendMessage (hList, LB_ADDSTRING, 0, (LPARAM) buffer);
    44.         //если первый символ следующей строки отличен от первого предыдущей
    45.         //значит все строки, начинающиеся этим символом, скопированы
    46.         //и переданы в листбокс. Можно выходить.
    47.         if ( *(lpText) != buffer[0] ) break;
    48.        
    49.         }
    50.    
    51. }
     
  18. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    Сотри свой код, а то будем обсуждать его (есть к чему придраться), а не предлагать свои варианты.



    как же должна выглядеть процедура

    Прежде чем приступать к реализации поясни:<ol type=1><li>наличие разных файлов для разных языков - обязательное условие;<li>упорядоченность строк в файле - обязательное условие или результат борьбы за скорость;<li>какого размера может быть файл.</ol>
     
  19. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    q_q,IceStudent

    Я вам про Фому, а вы мне про Ерему ;))

    X+j == X+j*sizeof(*X) справедливо когда выражение X является указателем

    В рассматриваемом же случае (int)lpText это просто число типа int, а (int*)lpText это указатель на число типа int. Поэтому при lpText = NULL выражение (int)lpText+j == j, а (int*)lpText+j == j*4

    Вопрос на засыпку: можно ли в си записать выражение (float)lpText+0.5 и если да, то чему оно будет равно ?
     
  20. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    leo

    Точно, проморгал.





    Теоретически - результат будет float, а значение таким и будет: (float)lpText+0.5.



    Практически:
    Код (Text):
    1.  
    2.     LPSTR lpText = "hello, world!";
    3.     printf("lpText = 0x%X (%d)\n",lpText,lpText);
    4.  
    5.     // cannot convert from 'LPSTR' to 'float'
    6.     float res = (float)lpText + 0.5;
    7.     // INTERNAL COMPILER ERROR
    8.     float res = static_cast<float>(reinterpret_cast<int>(lpText)) + 0.5;
    9.     float res = (float)((int)lpText) + 0.5;
    10.  
    11.     printf("(float)lpText = %f\n",res);
    12.  




    C1001 - это с O1, с Od в порядке (cl v13.10.3077)