Почему не было встроенного доступа к регистру состояния ЦП при разработке как C, так и C++?

В случае с флагом переполнения, казалось бы, доступ к этому флагу был бы большим благом для кросс-архитектурного программирования. Это обеспечило бы безопасную альтернативу использованию неопределенного поведения для проверки переполнения целого числа со знаком, например:

if(a < a + 100) //detect overflow

Я понимаю, что есть безопасные альтернативы, такие как:

if(a > (INT_MAX - 100)) //detected overflow

Однако может показаться, что доступ к регистру состояния или отдельным флагам в нем отсутствует как в языках C, так и в C++. Почему эта функция не была включена или какие языковые решения были приняты, чтобы запретить эту функцию?


person Timesquare    schedule 01.10.2012    source источник
comment
C и C++ должны были быть переносимыми. Не все процессоры имеют одинаковые регистры состояния ЦП.   -  person Mysticial    schedule 01.10.2012
comment
Исследуя этот вопрос, я не смог найти запись о процессоре, не имеющем флага переполнения. Встроенная функция может быть разбита на доступ к отдельным флагам, что позволит сделать ее переносимой.   -  person Timesquare    schedule 01.10.2012
comment
Операции SSE не имеют флагов переполнения. Компилятору разрешено реализовывать вещи, используя инструкции SSE.   -  person Mysticial    schedule 01.10.2012
comment
Хотя это и не имеет прямого отношения к ответу на этот вопрос, я бы сказал, что при первоначальной разработке C не было доступных инструкций SSE, поэтому проблема не повлияла на упущение этой функции.   -  person Timesquare    schedule 01.10.2012
comment
Не имеющий отношения. С точки зрения переносимости не имеет значения, есть или нет процессоры без флага. Это имеет значение только в том случае, если они могут или не могут быть построены.   -  person Analog File    schedule 01.10.2012
comment
@Timesquare: Тот факт, что могут быть архитектуры без флага, вероятно, повлиял на решения, хотя конкретный пример SSE не повлиял. Вы уверены, что все платформы, известные во времена стандарта C, имели недополнение?   -  person David Rodríguez - dribeas    schedule 01.10.2012
comment
Во время первоначального проектирования C были другие вещи. Например, процессоры, которые использовали дополнение, знак и абсолютное значение и другие особенности для реализации арифметики со знаком. Все они имеют совершенно разную семантику переполнения.   -  person Jan Hudec    schedule 01.10.2012
comment
Однажды я прочитал статью о неопределенном поведении, в которой говорилось о машине с необычной архитектурой для работы с переполнением — хотел бы я сейчас найти эту чертову штуку.   -  person Michael Burr    schedule 01.10.2012
comment
@Timesquare когда C был первоначально разработан, не было доступных инструкций SSE - Точно! вам не нужен язык, переносимый только для современного оборудования, во времена, когда оборудование развивается в темпе секунд (преднамеренное преувеличение). Портативность также означает готовность к будущему. Так что можно сказать, что это действительно повлияло на решение, пусть и не напрямую.   -  person Christian Rau    schedule 01.10.2012
comment
Примерно в 1980 году я использовал язык, в котором была переменная $CARRY. Однако вопрос следует адресовать Деннису Ритчи. Все, что вы получите здесь, будет догадками. Не конструктивно.   -  person user207421    schedule 02.10.2012


Ответы (3)


  • Because C++ is designed as a portable language, i.e. one that compiles on many CPUs (e.g. x86, ARM, LSI-11/2, with devices like Game Boys, Mobile Phones, Freezers, Airplanes, Human Manipulation Chips and Laser Swords).
    • the available flags across CPUs may largely differ
    • даже в пределах одного и того же процессора флаги могут отличаться (возьмите скалярные инструкции x86 против векторных инструкций)
    • некоторые процессоры могут вообще не иметь желаемого флага
  • Необходимо ответить на вопрос: Должен ли компилятор всегда устанавливать/включать этот флаг, если он не может определить, используется ли он вообще?, что не соответствует плате только за то, что вы использовать неписаный, но священный закон как C, так и C++
  • Поскольку компиляторам нужно было бы запретить оптимизировать и, например. переупорядочить код, чтобы сохранить эти флаги действительными

Пример для последнего:

int x = 7;
x += z;
int y = 2;
y += z;

Оптимизатор может преобразовать это в код псевдоассемблера:

alloc_stack_frame 2*sizeof(int)
load_int 7, $0
load_int 2, $1
add z, $0
add z, $1

который, в свою очередь, будет больше похож на

int x = 7;
int y = 2;
x += z;
y += z; 

Теперь, если вы запрашиваете регистры между

int x = 7;
x += z;
if (check_overflow($0)) {...}
int y = 2;
y += z;

то после оптимизации и дизассемблирования вы можете закончить следующим образом:

int x = 7;
int y = 2;
x += z;
y += z;
if (check_overflow($0)) {...}

что тогда неверно.

Можно было бы построить больше примеров, например, то, что происходит с переполнением времени компиляции с постоянным свертыванием.


Примечания: я помню старый компилятор Borland C++ с небольшим API для чтения текущих регистров процессора. Тем не менее, приведенная выше аргументация об оптимизации остается в силе.

С другой стороны: чтобы проверить переполнение:

// desired expression: int z = x + y
would_overflow = x > MAX-y;

более конкретно

auto would_overflow = x > std::numeric_limits<int>::max()-y;

или лучше, менее конкретно:

auto would_overflow = x > std::numeric_limits<decltype(x+y)>::max()-y;
person Sebastian Mach    schedule 01.10.2012

Потому что C и C++ спроектированы так, чтобы быть независимыми от платформы. Статус регистра нет.

В наши дни дополнение до двух повсеместно используется для реализации целочисленной арифметики со знаком, но так было не всегда. Раньше дополнение или знак и абсолютное значение были довольно распространены. И когда C был впервые разработан, такие процессоры все еще широко использовались. Например. COBOL различает отрицательный и положительный 0, которые существовали в этих архитектурах. Очевидно, что поведение переполнения на этих архитектурах совершенно другое!

Между прочим, вы не можете полагаться на неопределенное поведение для обнаружения переполнения, потому что разумные компиляторы увидев

if(a < a + 100)

напишет предупреждение и скомпилирует

if(true)

... (при условии, что оптимизации включены, а конкретная оптимизация не отключена).

И обратите внимание, что вы не можете полагаться на предупреждение. Компилятор выдаст предупреждение только тогда, когда условие заканчивается true или false после эквивалентных преобразований, но во многих случаях условие будет изменено при наличии переполнения, не заканчиваясь простым true/false.

person Jan Hudec    schedule 01.10.2012

Я могу предположить следующие причины.

  1. Разрешая доступ к регистровым флагам, переносимость языка между платформами сильно ограничивается.

  2. Оптимизатор может кардинально изменить выражения и сделать ваши флаги бесполезными.

  3. Это сделало бы язык более сложным

  4. Большинство компиляторов имеют большой набор встроенных функций для выполнения наиболее распространенных операций (например, сложения с переносом), не прибегая к флагам.

  5. Большинство выражений можно переписать безопасным способом, чтобы избежать переполнения.

  6. Вы всегда можете вернуться к встроенной сборке, если у вас есть очень специфические потребности.

Доступ к регистрам состояния кажется недостаточным для проведения стандартизации.

person mirk    schedule 01.10.2012