Input.h

Тема в разделе "WASM.LANGS", создана пользователем Intro, 8 май 2022.

Метки:
  1. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Стандартная библиотека С имеет для ввода с консоли функцию scanf. Эта функция очень плохо контролирует правильность ввода, и нормальные программисты настоятельно не рекомендуют её использовать, даже в простых программах. Так что пытаемся сделать аналог.
    Функции должны компилироваться(и работать начиная от 5150) начиная от TurboC 1.0 или 3.0 точно так что используем С89.
    Код (C):
    1.  
    2. /* Функции замены scanf
    3. Blackspace - стереть крайний символ
    4. Esc - стереть строку полностью
    5. Enter - ввести данные
    6. (c) Intro   8.05.2022
    7.  */
    8. #include <stdio.h>
    9. #include <string.h>
    10. #include <conio.h>
    11. #ifndef bool
    12. #define     bool        char
    13. #define     true        1
    14. #define     false       0
    15. #endif
    16. int InputInt()
    17. {
    18.     int     N;                  /* кол. введёных символов */
    19.     char    buf[15], buf2[15];
    20.     bool    negative = false;   /* фл. отрицательного числа */
    21.     int     res = 0;
    22.     for (N=0;;){
    23.         int S = getch();
    24.         if (S==13 && N>(negative ? 1 : 0))  break;  /* Enter */
    25.         if (S=='-' && N==0 && !negative){       /* минус */
    26.             negative = true;
    27.             buf[N++] = S; buf[N] = 0;
    28.             putchar(S);
    29.         }else if (S>='0' && S<='9'){    /* Цифры */
    30.             int     digit = (S-'0');
    31.             int     tmp = res*10 + (negative ? -digit : digit);
    32.             if (N==(negative ? 2 : 1) && buf[N-1]=='0'){    /* убираем лишние нули */
    33.                 --N;
    34.                 cputs("\b \b");
    35.             }
    36.             /* Ввод символа */
    37.             buf[N++] = S; buf[N] = 0;   /* символ и терм. нуль */
    38.             sprintf(buf2, "%d", tmp);
    39.             /* проверка переполнения */
    40.             if (strcmp(buf, buf2)!=0){
    41.                 buf[--N] = 0;
    42.                 putchar('\a');  /* гудок */
    43.                 continue;
    44.             }
    45.             res = tmp;
    46.             putchar(S);
    47.         }else if (S==27 || S==8){       /* Esc и Blackspace */
    48.             while (N>0){
    49.                 if (negative && N==1)
    50.                     negative = false;
    51.                 else
    52.                     res /= 10;
    53.                 buf[--N] = 0;
    54.                 cputs("\b \b");
    55.                 if (S==8) break;        /* Blackspace */
    56.             }
    57.         }
    58.     }
    59.     return res;
    60. }
    61. unsigned int InputUInt()
    62. {
    63.     int     N;              /* кол. введёных символов */
    64.     char    buf[15], buf2[15];
    65.     unsigned int    res = 0;
    66.     for (N=0;;){
    67.         int S = getch();
    68.         if (S==13 && N>0)   break;      /* Enter */
    69.         if (S>='0' && S<='9'){  /* Цифры */
    70.             unsigned int    tmp = res*10+(S-'0');
    71.             if (N==1 && buf[0]=='0'){   /* убираем лишние нули */
    72.                 --N;
    73.                 cputs("\b \b");
    74.             }
    75.             /* Ввод символа */
    76.             buf[N++] = S; buf[N] = 0;   /* символ и терм. нуль */
    77.             sprintf(buf2, "%u", tmp);
    78.             /* проверка переполнения */
    79.             if (strcmp(buf, buf2)!=0){
    80.                 buf[--N] = 0;
    81.                 putchar('\a');  /* гудок */
    82.                 continue;
    83.             }
    84.             res = tmp;
    85.             putchar(S);
    86.         }else if (S==27 || S==8){       /* Esc и Забой */
    87.             while (N>0){
    88.                 res /= 10;
    89.                 buf[--N] = 0;
    90.                 cputs("\b \b");
    91.                 if (S==8) break;        /* Забой */
    92.             }
    93.         }
    94.     }
    95.     return res;
    96. }
    97.  
    Пока нету для float и строк. Потом.
     
    Последнее редактирование: 8 май 2022
  2. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.331
    Проверять целое число на переполнение путем форматирования его в строку и сравнения строк, нормальные программисты тоже настоятельно не рекомендуют. Разве что это для govnokod.ru библиотека ввода, тогда не страшно :)
    --- Сообщение объединено, 8 май 2022 ---
    Intro,
    И кстати, если ты хочешь, чтобы компилилось любым компилем, то объявлять переменные можно только в начале функции до первого оператора и присваивать значение можно только после объявления переменной. То, что твой код компилится - это просто у мс такой c89, с блекджеком и шл.хами :)

    Код (C):
    1.  
    2. int main ()
    3. {
    4.     int i, result;
    5.  
    6.     result = 0; /* int result = 0 - нельзя */
    7.  
    8.     for (i=0; ...) /* for (int i=0; ...)  - нельзя */
    9.     {
    10.         /* int j; внутри цикла нельзя */
    11.         /* однострочных комментариев в бородатом си тоже нет, кстати :) */
    12.     }
    13.  
    14.     return result;
    15. }
    16.  
     
    youneuoy нравится это.
  3. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Не придумал ничего лучшего, кроме того хотел получить код для шаблонов С++. Не понятно чего просто tmp>MAX_INT где tmp это long long int не работает, не работает и всё. Ассемблер рулит, там это работает. Это просто костыли, но они работают, а значит это нормальный код.
    По идеи должно быть так.
    Код (C++):
    1. try {
    2.     tmp = res*10 + (negative ? -digit : digit);
    3.  } catch (integer_overflow) {
    4.      buf[--N] = 0;
    5.      putchar('\a'); /* гудок */
    6.      continue;
    7.  }
    Но это С++, и я не знаю можно ли отследить переполнение таким образом. Технически это очень легко можно сделать на любых, абсолютно любых системах, т.к. carry есть везде.
     
  4. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.331
    Intro,
    Я же тебе в другом топике показал, как отслеживать переполнения ДО того, как оно произойдет.
    Добавление разряда к целому - value = value * 10 + digit. Максимальное значение для uint32 - 4294967295. Таким образом, если текущее значение value меньше 429496729, можно спокойно добавлять следующий разряд, переполнения гарантированно не будет. Если текущее значение равно 429496729, то добавить без переполнения можно только разряд со значением 0..5. Если же текущее значение больше 429496729, то никакой разряд добавить нельзя, переполнение будет гарантированно.

    Код (C):
    1.  
    2. static bool AppendDigit (uint32* value, int digit/* 0..9 */, bool isSigned)
    3. {
    4.     if (isSigned)
    5.     {
    6.         if (value > 429496729 || (value == 429496729 && digit > 5))
    7.             return FALSE;
    8.     }
    9.     else if (value > 214748364 || (value == 214748364 && digit > 7))
    10.         return FALSE;
    11.    
    12.     *value = *value * 10 + digit;
    13.  
    14.     return TRUE;  
    15. }
    16.  
    17. uint32 ReadInt (bool* isSigned/* out */)
    18. {
    19.     uint32 value;
    20.     int c, sign, length;
    21.  
    22.     value = 0;
    23.     length = 0;
    24.     sign = 0;
    25.        
    26.     while (TRUE)
    27.     {
    28.         c = GetChar();
    29.        
    30.         if (IsDigit (c))
    31.         {
    32.             if (!AppendDigit (&value, c - '0', sign == '-'))
    33.             {
    34.                 // overflow
    35.             }
    36.             else
    37.             {
    38.                 length++;
    39.                 PutChar (c);
    40.             }
    41.         }
    42.         else if (c == '-' || c == '+')
    43.         {
    44.             if (sign != 0 || length != 0)
    45.             {
    46.                 // invalid character
    47.             }
    48.             else
    49.             {
    50.                 sign = c;
    51.                 length++;
    52.                 PutChar (c);
    53.             }
    54.         }
    55.         else if (c == '\b')
    56.         {
    57.             if (length != 0)
    58.             {
    59.                 PutChar (c);
    60.                 value /= 10;
    61.                 length--;
    62.             }
    63.         }
    64.         else if (c == 27)
    65.         {
    66.             while (length--)
    67.                 PutChar ('\b');
    68.            
    69.             value = 0;
    70.             sign = 0;
    71.             length = 0;
    72.         }
    73.         else if (c == '\n')
    74.         {
    75.             if (length != 0)
    76.                 break;
    77.         }
    78.         else
    79.         {
    80.             // invalid character
    81.         }
    82.     }
    83.  
    84.     if (sign == '-')
    85.     {
    86.         *isSigned = TRUE;
    87.        
    88.         value = ~value + 1;
    89.     }
    90.     else
    91.         *isSigned = FALSE;
    92.        
    93.     return value;
    94. }
    95.  
     
  5. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Ага смог победить компиляхтор, возьми с полки пирожок.
    Но мой код хорошо натягивается на шаблоны С++, разных типов целых от байта до __m128 или __m256
    Быстродействие? Ну тут это совершенно не актуально, даже для 8088, там в getch основное время ожидание.
     
  6. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.331
    Ну ок, натягивай дальше :)
     
  7. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.956
    Предлагаю для полноты треша и угара printf'ить не само число, а все выражение целиком, потом evaluate'ить vbs'ом, перенаправлять выхлоп в файл и читать из него результат. Кампуцеры нонча мощные, не треснут.
     
  8. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.331
    f13nd,
    И все это в докер на пару гигов, шоб от окружения пользователя не зависеть :)
     
  9. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Да я понял, я дурак!
    if (res>MAX_UINT/10 || (res== MAX_UINT/10 &&res> MAX_UINT %10))

    Просто надо было выпить водочки стакан. Точней даже 250 мл
    И это код так же ложиться на шаблоны С++.
    --- Сообщение объединено, 11 май 2022 ---
    Точней так
    Код (C):
    1.  
    2. /* проверка переполнения */
    3. if (res>UINT_MAX/10 || (res==UINT_MAX/10 &&  (S-'0')>UINT_MAX%10)){
    4.  
     
  10. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Обновил код, но прежний мне больше нравиться. Все, ну почти все, ну многие современные погромисты так пишут, причём даже в отвественных местах. И даже получают тыщи деняг
    Код (C):
    1.  
    2. /* Функции замены scanf   ver 0.01
    3. Blackspace - стереть крайний символ
    4. Esc - стереть строку полностью
    5. Enter - ввести данные
    6. (c) Intro   8.05.2022   14.05.2022
    7.  */
    8. #include <stdio.h>
    9. //#include <string.h>
    10. #include <conio.h>
    11. #include <limits.h>
    12. #ifndef bool
    13. #define     bool        char
    14. #define     true        1
    15. #define     false       0
    16. #endif
    17. int InputInt()
    18. {
    19.     int     res, N;                 /* кол. введёных символов */
    20.     char    buf[15];
    21.     bool    negative = false;   /* фл. отрицательного числа */
    22.     for (N=0, res=0;;){
    23.         int S = getch();
    24.         if (S==13 && N>(negative ? 1 : 0))  break;  /* Enter */
    25.         if (S=='-' && N==0 && !negative){       /* минус */
    26.             negative = true;
    27.             buf[N++] = S; buf[N] = 0;
    28.             putchar(S);
    29.         }else if (S>='0' && S<='9'){    /* Цифры */
    30.             int digit;
    31.             if (N==(negative ? 2 : 1) && buf[N-1]=='0'){    /* убираем лишние нули */
    32.                 --N;
    33.                 cputs("\b \b");
    34.             }
    35.             digit = negative ? -(S-'0') : (S-'0');
    36.             /* проверка переполнения */
    37.             if (negative && (res<INT_MIN/10 || (res==INT_MIN/10 && digit<INT_MIN%10)) ||
    38.                 (res>INT_MAX/10 || (res==INT_MAX/10 && digit>INT_MAX%10))){
    39.                 putchar('\a');  /* гудок */
    40.                 continue;
    41.             }
    42.             /* Ввод символа */
    43.             buf[N++] = S; buf[N] = 0;   /* символ и терм. нуль */
    44.             res = res*10 + digit;
    45.             putchar(S);
    46.         }else if (S==27 || S==8){       /* Esc и Blackspace */
    47.             while (N>0){
    48.                 if (negative && N==1)
    49.                     negative = false;
    50.                 else
    51.                     res /= 10;
    52.                 buf[--N] = 0;
    53.                 cputs("\b \b");
    54.                 if (S==8) break;        /* Blackspace */
    55.             }
    56.         }
    57.     }
    58.     return res;
    59. }
    60. unsigned int InputUInt()
    61. {
    62.     int     N;              /* кол. введёных символов */
    63.     char    buf[15];
    64.     unsigned int    res;
    65.     for (N=0, res=0;;){
    66.         int S = getch();
    67.         if (S==13 && N>0)   break;      /* Enter */
    68.         if (S>='0' && S<='9'){          /* Цифры */
    69.             int digit;
    70.             if (N==1 && buf[0]=='0'){   /* убираем лишние нули */
    71.                 --N;
    72.                 cputs("\b \b");
    73.             }
    74.             digit = S-'0';
    75.             /* проверка переполнения */
    76.             if (res>UINT_MAX/10 || (res==UINT_MAX/10 && digit>UINT_MAX%10)){
    77.                 putchar('\a');  /* гудок */
    78.                 continue;
    79.             }
    80.             /* Ввод символа */
    81.             res = res*10+digit;
    82.             buf[N++] = S; buf[N] = 0;   /* символ и терм. нуль */
    83.             putchar(S);
    84.         }else if (S==27 || S==8){       /* Esc и Забой */
    85.             while (N>0){
    86.                 res /= 10;
    87.                 buf[--N] = 0;
    88.                 cputs("\b \b");
    89.                 if (S==8) break;        /* Забой */
    90.             }
    91.         }
    92.     }
    93.     return res;
    94. }
    95.  
     
  11. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    562
    Код (C):
    1.  
    2. /* Функции замены scanf   ver 0.02
    3. Blackspace - стереть крайний символ
    4. Esc - стереть строку полностью
    5. Enter - ввести данные
    6. (c) Intro   8.05.2022   18.05.2022
    7.  */
    8. #include <stdio.h>
    9. #include <conio.h>
    10. #include <limits.h>
    11. int InputInt()
    12. {
    13.     int     res, N;         /* кол. введёных символов */
    14.     int     negative;       /* фл. отрицательного числа */
    15.     for (N=0, res=0, negative=0;;){
    16.         int S = getch();
    17.         if (S==13 && N>negative) break; /* Enter */
    18.         if (S=='-' && N==0 && !negative){   /* минус */
    19.             negative = 1;
    20.             N++;
    21.             putchar(S);
    22.         }else if (S>='0' && S<='9'){    /* Цифры */
    23.             int digit;
    24.             if (N==(negative+1) && res==0){ /* убираем лишние нули */
    25.                 --N;
    26.                 cputs("\b \b");
    27.             }
    28.             digit = S-'0';
    29.             if (negative) digit = -digit;
    30.             /* проверка переполнения */
    31.             if (negative && (res<INT_MIN/10 || res==INT_MIN/10 && digit<INT_MIN%10) ||
    32.                 (res>INT_MAX/10 || res==INT_MAX/10 && digit>INT_MAX%10)){
    33.                 putchar('\a');  /* гудок */
    34.                 continue;
    35.             }
    36.             /* Ввод символа */
    37.             res = res*10 + digit; ++N;
    38.             putchar(S);
    39.         }else if (S==27 || S==8){       /* Esc и Blackspace */
    40.             while (N>0){
    41.                 if (negative && N==1)
    42.                     negative = 0;
    43.                 else
    44.                     res /= 10;
    45.                 --N;
    46.                 cputs("\b \b");
    47.                 if (S==8) break;        /* Blackspace */
    48.             }
    49.         }
    50.     }
    51.     return res;
    52. }
    53. unsigned int InputUInt()
    54. {
    55.     int     N;              /* кол. введёных символов */
    56.     unsigned int    res;
    57.     for (N=0, res=0;;){
    58.         int S = getch();
    59.         if (S==13 && N>0)   break;      /* Enter */
    60.         if (S>='0' && S<='9'){          /* Цифры */
    61.             int digit;
    62.             if (N==1 && res==0){        /* убираем лишние нули */
    63.                 --N;
    64.                 cputs("\b \b");
    65.             }
    66.             digit = S-'0';
    67.             /* проверка переполнения */
    68.             if (res>UINT_MAX/10 || (res==UINT_MAX/10 && digit>UINT_MAX%10)){
    69.                 putchar('\a');  /* гудок */
    70.                 continue;
    71.             }
    72.             /* Ввод символа */
    73.             res = res*10+digit; ++N;
    74.             putchar(S);
    75.         }else if (S==27 || S==8){       /* Esc и Blackspace */
    76.             while (N>0){
    77.                 res /= 10; --N;
    78.                 cputs("\b \b");
    79.                 if (S==8) break;        /* Blackspace */
    80.             }
    81.         }
    82.     }
    83.     return res;
    84. }
    85.  
    Так уже лучше, ничего лишнего.
     
  12. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.331
    Там целая функция лишняя :)