Блог пользователя Na2a

Автор Na2a, история, 8 лет назад, перевод, По-русски

Привет, Codeforces

Вчера, на 366-ом раунде мой друг Birjik столкнулся со странной проблемой. Его правильный код получал ошибку исполнения на примерах.

Взгляните на следующие коды:
Runtime error
Accepted

Вы можете заметить, что код с RE имеет такие строки:

ios_base::sync_with_stdio(0);
cin.tie(0);

Странно, не так ли?
Насколько я понял, это случается поскольку в коде имеется массив с названием "read".
Переименование массива решает эту проблему.

Вкратце, использование ios_base / cin.tie получает ошибку исполнения если мы имеем переменную с названием "read".
Будьте внимательны!

  • Проголосовать: нравится
  • +181
  • Проголосовать: не нравится

»
8 лет назад, # |
  Проголосовать: нравится +58 Проголосовать: не нравится

Минимально воспроизводящийся пример

#include <iostream>

using namespace std;

int read;

int main(){
    ios_base::sync_with_stdio(0);

    int n;
    cin >> n;
    return n;
}

Сборка: g++ -o main main.cpp -fsanitize=address

»
8 лет назад, # |
  Проголосовать: нравится -69 Проголосовать: не нравится

cin/cout — зло

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Переменную write тоже нельзя использовать. И да, под MS C++ все нормально.

»
8 лет назад, # |
  Проголосовать: нравится +8 Проголосовать: не нравится

http://www.gdsw.at/languages/c/programming-bbrown/c_075.htm

В C и C++ есть функции int read int write. Возможно из-за глобальной переменной с таким же именем и типом происходит конфликт в синхронизации?

  • »
    »
    8 лет назад, # ^ |
      Проголосовать: нравится +30 Проголосовать: не нравится

    Да, похоже на правду. Название символа как для стандартной функции

    ssize_t read(int fildes, void *buf, size_t nbyte);

    так и для глобальной переменной read одинаково — read. При компоновке программы адрес переменной подставляется туда, где должна была быть вызвана одноимённая функция. Попытка вызова переменной как функции приводит к ошибке.

    Вот как это выглядит в отладчике:

    #0  0x00000000006015a0 in read ()
    #1  0x00007ffff6b61567 in std::__basic_file<char>::xsgetn (this=this@entry=0x7ffff6e34488 <__gnu_internal::buf_cin+104>, __s=0x62500000a100 '\276' <repeats 200 times>..., __n=__n@entry=8191)
        at basic_file.cc:292
    #2  0x00007ffff6b9e5e6 in std::basic_filebuf<char, std::char_traits<char> >::underflow (this=0x7ffff6e34420 <__gnu_internal::buf_cin>)
        at /build/gcc-multilib/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/fstream.tcc:320
    #3  0x00007ffff6baa339 in std::basic_streambuf<char, std::char_traits<char> >::sgetc (this=0x7ffff6e34420 <__gnu_internal::buf_cin>)
        at /build/gcc-multilib/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/streambuf:344
    #4  std::istream::sentry::sentry (this=0x7fffffffdfeb, __in=..., __noskip=<optimized out>) at /build/gcc-multilib/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/istream.tcc:58
    #5  0x00007ffff6baa51e in std::istream::operator>> (this=0x601440 <std::cin@@GLIBCXX_3.4>, __n=@0x7fffffffe040: -7800)
        at /build/gcc-multilib/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/istream.tcc:163
    #6  0x0000000000400bbb in main () at x.cpp:11
    

    Адрес переменной совпадает:

    00000000006015a0 B read
»
8 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

Workarounds: mark the variable static, put it into an anonymous namespace, put it into a named namespace/class, or don't use global variables.