Comments 32
В CompCert нет ошибки — там жопа ваще.
+72
Только и пришло на ум — «как страшно жить». Если у человека 4 компилятора показали ошибку, то как верить, скажем, ПО кардиоводителя, или ПО системы жизнеобеспечения космического корабля, особенно, если на борту люди?
Впрочем, какая жизнь без риска? :)
Впрочем, какая жизнь без риска? :)
+1
Там не верят, а проверяют. Решение в многочисленных и разнообразных тестах, которые покрывают максимум ситуаций. Т.к. в некоторых случаях ошибка может произойти, но будет не значительна. Точно так же, как любое техническое устройство может дать аппаратный сбой.
Собственно поэтому один из вариантов — берут показатели 3х вычислений и сравнивают.
Собственно поэтому один из вариантов — берут показатели 3х вычислений и сравнивают.
0
> Обычные арифметические преобразования подразумевают, что оба операнда к оператору "+" должны быть преобразованы из типа «signed char» к типу «signed int» перед выполнением операции сложения.
Не так.
Если, к примеру, сложить 2 signed char'a то никаких преобразований не будет.
В данном случае они есть только потому что выполняется согласование типов — меньший (signed char: x) кастуется к большему (signed int: 1).
Константа 1 это signed int просто потому что нет постфикса (u/l/ll) и она вмещается в int.
Порядок проверки вместимости — int, long int, long long int.
То есть числовая константа никогда не может быть short или char, собственно поэтому и кастуется, а не из-за каких-то странных мыслей в голове автора.
Не так.
Если, к примеру, сложить 2 signed char'a то никаких преобразований не будет.
В данном случае они есть только потому что выполняется согласование типов — меньший (signed char: x) кастуется к большему (signed int: 1).
Константа 1 это signed int просто потому что нет постфикса (u/l/ll) и она вмещается в int.
Порядок проверки вместимости — int, long int, long long int.
То есть числовая константа никогда не может быть short или char, собственно поэтому и кастуется, а не из-за каких-то странных мыслей в голове автора.
+5
А если быть точнее, то не «кастуется», а «промоутиться». Отличия — см. в стандарте.
+2
Вы удиветесь, но в стандарте чётко написано, что вся знаковая целочисленная арифметика выполняется с int-ами, если по размеру подходит, если не подходит, то с long int-ами. Если вы не заметили преобразования, или если оптимизатор его выкинул, то это ещё не означает, что его не было :)
+2
Действительно удивлюсь.
Покажите пруф, что ли.
Additive operators: 6.5.6, item 4 — «If both operands have arithmetic type, the usual arithmetic conversions are performed on
them»
arithmetic type: 6.2.5, item 18: "Integer and floating types are collectively called arithmetic types"
Integer types: 6.2.5, item 17: «The type char, the signed and unsigned integer types, and the enumerated types are collectively called integer types»
usual arithmetic conversions: 6.3.1.8, item 11: "флоаты... If both operands have the same type, then no further conversion is needed. условие выполнилось, дальше читать не нужно"
В общем если по-русски, то char — это целочисленный тип, целочисленный тип это арифметический тип.
Арифметические типы при сложении следуют общем правилам кастинга бинарных операторов. Первое же правило для целых чисел — если типы одинаковые, то всё ок, оставляем так.
Где здесь принудительная конвертация я не увидел.
Особенно если учесть ремарки о том, что неявная конвертация прописывается только в соответствующих главах про выражения. (6.5.xxx)
Покажите пруф, что ли.
Additive operators: 6.5.6, item 4 — «If both operands have arithmetic type, the usual arithmetic conversions are performed on
them»
arithmetic type: 6.2.5, item 18: "Integer and floating types are collectively called arithmetic types"
Integer types: 6.2.5, item 17: «The type char, the signed and unsigned integer types, and the enumerated types are collectively called integer types»
usual arithmetic conversions: 6.3.1.8, item 11: "флоаты... If both operands have the same type, then no further conversion is needed. условие выполнилось, дальше читать не нужно"
В общем если по-русски, то char — это целочисленный тип, целочисленный тип это арифметический тип.
Арифметические типы при сложении следуют общем правилам кастинга бинарных операторов. Первое же правило для целых чисел — если типы одинаковые, то всё ок, оставляем так.
Где здесь принудительная конвертация я не увидел.
Особенно если учесть ремарки о том, что неявная конвертация прописывается только в соответствующих главах про выражения. (6.5.xxx)
-1
Нет, это не так:
Запустите этот код у себя, компилятор вам скажет, что он думает о типах. В Стандарте это прописано в правилах о integral promotions
#include <stdio.h>
#include <typeinfo>
int main () {
char x = 1;
int i = 1;
printf("type:%s\n", typeid(x+x).name());
printf("type:%s\n", typeid(x).name());
printf("type:%s\n", typeid(i).name());
return 0;
}
Запустите этот код у себя, компилятор вам скажет, что он думает о типах. В Стандарте это прописано в правилах о integral promotions
+3
Ужас какой.
Какие-то совершенно детские ошибки в компиляторах, которые и современные, и распространённые.
Какие-то совершенно детские ошибки в компиляторах, которые и современные, и распространённые.
-1
на платформах, где char — знаковый тип
Наличие знака скорее зависит не от платформы, а от опций компилятора (опций по умолчанию и опций, задаваемых вручную). В частности, есть повсеместная практика при разработке мультиархитектурных программ и библиотек прописывать для clang или gcc
-funsigned-char
.Так вот, если использовать
-funsigned-char
, то в GCC 4.4/4.5/4.6/4.7 и Clang месячной давности всё работает правильно с любыми оптимизациями (1 1 1… 1 1 0).+4
А при опции -fsigned-char результат разный в зависимости от опций оптимизации. А обязан быть одинаковым.
Это баг.
Это баг.
0
++x — undefined behaviour, с чего бы результат должн быть одинаовый?
0
Ох, да. В Стандарте прописано, что только для беззнаковых целых гарантируется отсутствие реакции на переполнение (результат обязан усекаться).
Для знаковой арифметики — да, undefined behavior.
Для знаковой арифметики — да, undefined behavior.
0
Запутали вы меня. Как выглядит обоснование, что ++x — это именно undefined behavior, а не implementation-defined behavior?
0
Это не undefined behavior, а Implementation-defined:
C99, 6.3.1.3:3
«Otherwise, the new type is signed and the value cannot be represented in it; either the
result is implementation-defined or an implementation-defined signal is raised.»
C99, 6.3.1.3:3
«Otherwise, the new type is signed and the value cannot be represented in it; either the
result is implementation-defined or an implementation-defined signal is raised.»
0
Да, именно. Этот «undefined behavior» — только для таких экзотических платформ, у которых (INT_MAX+1) вызывает реакцию, аналогичную делению на ноль.
Все остальные должны четко прописывать, что именно должно получаться в результате. У GCC же результат «плавает».
В багзилле этот баг живёт уже 4 (!) года.
Все остальные должны четко прописывать, что именно должно получаться в результате. У GCC же результат «плавает».
В багзилле этот баг живёт уже 4 (!) года.
0
Да, правильно, implementation defined. Но undefined behavior — это тоже вариант решения проблемы implementation defined. И gcc приняло такую позицию, видимо.
0
int foo (signed char x) {
signed char y = x;
//x++; // #1
x=x+1; // #2
return x > y;
}
Строки #1 и #2 должны быть эквивалентны для компилятора. Однако, они приводят к разным результатам у GCC.
Это баг.
+2
Вот здесь баг, согласен. Так как инкремент и сравнение разделены точкой следования. А значит x должен был принять какое-то значение, которое в соотвествии с его типом не может быть больше SCHAR_MAX.
0
Совсем не должны они быть эквивалентны.
А вот если поменяете строку #2 на:
x = x + (signed char)1;
тогда можно будет об этой эквивалентности говорить.
А вот если поменяете строку #2 на:
x = x + (signed char)1;
тогда можно будет об этой эквивалентности говорить.
0
Почему? Откуда это следует?
0
потому что в случае
в правой части сложение не двух signed char, а signed char и int, а это значит, что первый операнд неявно расширяется до int. При x++; такого не происходит.
signed char x = 'a';
x = x + 1;
в правой части сложение не двух signed char, а signed char и int, а это значит, что первый операнд неявно расширяется до int. При x++; такого не происходит.
0
Ещё раз повторю вопрос: откуда вы это взяли?
Т.к. (как я это вижу в Стандарте) при x++ происходит следующее:
1. вычисляется x + 1:
1.1. «x» расширяется до int.
1.2. вычисляется результат (int(x) + 1)
2. Полученный результат (типа int) присваивается переменной «x»:
2.1. Так как int «шире», чем «signed char», то происходит усечение до типа «signed char»
2.2. Усечённый результат заносится в «x»
Всё. Этот порядок следует из эквивалентности выражений x++ и x=x+1. Где в Стандарте упоминается обратное?
Т.к. (как я это вижу в Стандарте) при x++ происходит следующее:
1. вычисляется x + 1:
1.1. «x» расширяется до int.
1.2. вычисляется результат (int(x) + 1)
2. Полученный результат (типа int) присваивается переменной «x»:
2.1. Так как int «шире», чем «signed char», то происходит усечение до типа «signed char»
2.2. Усечённый результат заносится в «x»
Всё. Этот порядок следует из эквивалентности выражений x++ и x=x+1. Где в Стандарте упоминается обратное?
0
char+char=int, это из стандарта следует и это так. Так что указанное Вами приведение типа не влияет.
0
Если бы речь шла о embedded, то у вас даже не возникло бы такого вопроса.
0
Есть пару статей, не связанных напрямую с описанной проблемой, но тоже интересно почитать: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
+2
Sign up to leave a comment.
Маленькая C-функция из преисподней