Как значения выражений сохраняются до того, как они будут присвоены в C? - PullRequest
2 голосов
/ 13 июля 2020

Здесь вопрос для начинающих; в C, когда вы присваиваете числовое значение переменной, язык дает понять, что переменная имеет определенный c тип, который может содержать только определенный c диапазон числовых значений. Если значение, присвоенное переменной, выходит за пределы диапазона, определенного ее типом, оно будет переполнено. Пример;

char foo = 1000;

здесь foo не ожидается равным 1000. Я полагаю, что присвоение включает значение выражения, которое должно быть приведено к типу переменной, следовательно, присвоение потенциально может изменить значение выражения в зависимости от того, происходит переполнение или нет, что зависит от типа переменной и значения выражения. В более сложных случаях (не жестко запрограммированных значений) я полагаю, что значение, которое будет храниться в памяти, неизвестно до того, как на самом деле произойдет присвоение.

Мой вопрос: во время выполнения кода, как значения выражений сохраняются до их назначения?

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

Как приложение этого вопроса; возможно ли написать выражение, включающее жестко запрограммированное число, настолько большое, что оно фактически не может быть правильно сохранено во время выполнения? Представьте себе жестко запрограммированное выражение, включающее число, немного большее, чем максимально возможное значение, разделенное на два, так что выражение теоретически дает представимое число, но это не так.

Ответы [ 2 ]

4 голосов
/ 13 июля 2020

Мой вопрос; во время выполнения кода, как значения выражений сохраняются до их назначения?

Обычно они сохраняются в коде как константы, например:

movb   $-0x18, -0x11(%rbp)

Это -0x18 - это константа -24, сохраняемая в некоторой ячейке памяти.

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

Вправо. Мой компилятор предупреждает меня: Implicit conversion from 'int' to 'char' changes value from 1000 to -24

В качестве приложения этого вопроса; возможно ли написать выражение, включающее жестко запрограммированное число, настолько большое, что оно фактически не может быть правильно сохранено во время выполнения?

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

char foo = 1000/8;

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

2 голосов
/ 13 июля 2020

Обычно каждое выражение в C, включая часть выражения внутри другого выражения, имеет тип. Для идентификаторов объявляется тип. Для констант или литералов тип является следствием формы и значения константы или литерала. Для результатов операторов тип определяется типами операндов и правилами для оператора.

Например, для целочисленных констант есть таблица в C 2018 6.4.4.1 5. Для десятичные константы без суффикса (например, l для long), он говорит, что тип является первым из int, long int и long long int, который может представлять значение. В следующем абзаце также говорится, что, если значение не соответствует ни одному из них, оно может соответствовать некоторому расширенному целочисленному типу, предоставленному реализацией C. Он также говорит, что значение не может быть представлено каким-либо типом в своем списке, и оно «не имеет типа». Если константа не имеет типа, то программа нарушает ограничение в разделе ограничений 6.4.4 2, в котором говорится: «Каждая константа должна иметь тип…», и поведение не определяется стандартом C. Когда программа нарушает ограничение, указанное в разделе ограничений, компилятор должен выдать для этого сообщение диагностики c.

Для многих операторов правила говорят, что целочисленные операнды продвигаются на ширину не менее int. (Есть некоторые технические особенности, которые я здесь опускаю, но это основной эффект целочисленных рекламных акций.) Это означает, что вы не можете выполнять арифметические операции c на только a char или short, где в реализация C, в которой эти типы уже, чем int. Кроме того, для многих операторов с двумя операндами операнды преобразуются в некоторый общий тип, как правило, в «больший» тип (хотя, опять же, есть некоторые технические особенности, которые могут быть более проблематичными из-за преобразований между знаковыми и беззнаковыми типами).

Все эти правила о типах влияют на значения , которые будут получены в результате вычисления выражений. Если вы добавите какое-то значение типа X к некоторому значению типа Y и умножите на какое-то значение типа Z , правила будут применяться для определения того, какое значение полученные результаты. Но в правилах не сказано, как должно быть представлено значение, пока программа работает с выражением. Компилятор может сгенерировать код, который обрабатывает значения в регистрах, который сохраняет некоторые константы в непосредственных полях инструкций, который создает некоторые константы на лету во время выполнения программы, который не содержит фактических инструкций, выполняющих явные операции, поскольку компилятор оптимизировал выражение для другая форма и многое другое. Стандарт C требует, чтобы значение было представлено только определенным образом, когда оно хранится в объекте (память зарезервирована для хранения значения, как в случае определения переменной). (И даже это можно удалить путем оптимизации, если программа ведет себя таким же образом в отношении наблюдаемых эффектов, как определено стандартом C.)

...