Перейти к содержанию
    

Возникла непонятка.

Использую деление переменной типа int на значение, возвращаемое функцией sizeof():

 

int t;

...

t = t / sizeof(buf);

if (t < 0) ...

else ...

 

Так вот - знак t может быть различный, но после деления на sizeof() компилятор считает, что знак результата становится положительный и отбрасывает ветку кода для обработки отрицательного значения. Даже функция деления используется беззнаковая.

Если вместо sizeof() подставить константу, то всё начинает работать как положено.

 

Что я делаю не так, подскажите?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

int t;

...

t = t / sizeof(buf);

if (t < 0) ...

else ...

 

Результат sizeof() - беззнаковый, оттого и все выражение становится таким. Приведите его явно к знаковому типу, и все устаканится:

t /= (int)sizeof(buf);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Результат sizeof() - беззнаковый, оттого и все выражение становится таким.

Понятно, мпасибо.

Но разве не должно быть наоборот - если хоть один операнд знаковый, то результат становится знаковым?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если перейдете на С++ (язык с более строгим контролем соответствия типов данных) , то компилятор по-хорошему должен выдать сообщение об ошибке и потребовать явного приведения к типу. Всякого рода умолчания тут вредны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Результат sizeof() - беззнаковый, оттого и все выражение становится таким. Приведите его явно к знаковому типу, и все устаканится:

t /= (int)sizeof(buf);

А не боитесь, что sizeof(buf) станет отрицательным. На "малых" значениях sizeof(buf) положительный и знак определяется только t, для "больших" значений sizeof(buf) отрицательный, и результат зависит от обоих знаков.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программа и так компилируется в плюсах, какого-то специального варнинга не видел.

Если вместо sizeof() использовать const unsigned char size = 20, то проблем со знаком нет, результат получается со знаком.

Не глюк ли это компилятора? Как еще это можно обьяснить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А не боитесь, что sizeof(buf) станет отрицательным. На "малых" значениях sizeof(buf) положительный и знак определяется только t, для "больших" значений sizeof(buf) отрицательный, и результат зависит от обоих знаков.

 

Ничуть не боюсь :), т.к. если делитель вылез из разрядной сетки целого, которая оказалась для него тесновата, а делимое t поместилось, то вряд ли можно получить какое-то частное, кроме нуля.

 

Опять же buf размером в 2 гигабайта на AVR-микроконтроллере едва ли возможен. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программа и так компилируется в плюсах, какого-то специального варнинга не видел.

Если вместо sizeof() использовать const unsigned char size = 20, то проблем со знаком нет, результат получается со знаком.

Не глюк ли это компилятора? Как еще это можно обьяснить?

здесь у Вас unsigned char (8 бит), а t имеет тип int (16 бит).

И надо учитывать, что sizeof возвращает не unsigned char, и даже не unsigned int, а size_t.

 

Думаю, Вам надо посмотреть как конкретно на вашем компиляторе реализуется тип size_t.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программа и так компилируется в плюсах, какого-то специального варнинга не видел.

Если там gcc, то за это предупреждение отвечает флаг -Wsign-compare.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если перейдете на С++ (язык с более строгим контролем соответствия типов данных) , то компилятор по-хорошему должен выдать сообщение об ошибке и потребовать явного приведения к типу. Всякого рода умолчания тут вредны.

Это именно C++.

А в чём именно ошибка? Int делим на Short (или любой другой тип без знака). В результате будет Int. Это ошибка?

 

И надо учитывать, что sizeof возвращает не unsigned char, и даже не unsigned int, а size_t.

Функция у sizeof() - вернуть константу, то есть самое обычное число без знака. Каким образом её результат может влиять на знак выражения типа: -100/х = y?

 

Если там gcc, то за это предупреждение отвечает флаг -Wsign-compare.

Проверил на других компиляторах: IAR и CodeVision не страдают этой ошибкой и генерят код в соответствии с математическими правилами и моими ожиданиями.

А вот GCC в AtmelStudio и для ARMов точно также отбрасывает знак и считает, что результат может быть только положительный.

Прискорбно :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это именно C++.

А в чём именно ошибка? Int делим на Short (или любой другой тип без знака). В результате будет Int. Это ошибка?

Строго говоря, ошибка.

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

 

PS. Short - не обязательно беззнаковый тип

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вот GCC в AtmelStudio и для ARMов точно также отбрасывает знак и считает, что результат может быть только положительный.

Прискорбно :(

Это не прискорбно, это - в соответствии со стандартом.

Вот что говорится в ISO/IEC 9899:1999 6.3.1.8 Usual arithmetic conversions:

Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

  • If both operands have the same type, then no further conversion is needed.
  • Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
  • Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
  • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then

    the operand with unsigned integer type is converted to the type of the operand with signed integer type.

  • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

 

Ваш вариант - последний (поскольку int не может вместить всех значений size_t, size_t - не может вместить всех значений int, то побеждает size_t, как беззнаковый.)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... и еще вот тут есть интересные рассуждения про size_t

 

http://www.embedded.com/electronics-blogs/...-size-t-matters

 

Переведу-ка я ее на русский, да опубликую не сегодня-завтра в своем блоге.

Полезное ведь дело, однако, да.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ваш вариант - последний (поскольку int не может вместить всех значений size_t, size_t - не может вместить всех значений int, то побеждает size_t, как беззнаковый.)

Тогда обязан был быть ворнинг или даже еррор, так как в результате такого преобразования разрушается значение Int.

Но никакого предупреждения компилер не дает.

 

Вероятно, более продвинутые компиляторы понимают, что в моём случае sizeof() даёт размерность, которая умещается в простом char, и, соответственно, не преобразуют Int.

Для GCC это непосильная задача :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вероятно, более продвинутые компиляторы понимают, что в моём случае sizeof() даёт размерность, которая умещается в простом char, и, соответственно, не преобразуют Int.

Для GCC это непосильная задача :(

1. sizeof() возвращает size_t, независимо от значения.

2. int/size_t возвращает size_t. (при условии sizeof(int) == sizeof(size_t) )

Это требование стандарта.

Вы считаете, что несоблюдение компилятором стандарта языка говорит о том, что этот компилятор "более продвинутый"? :)

 

Кстати, есть вариант, что в этих продвинутых компиляторах int просто длиннее, чем size_t, и поэтому всё получается нормально без нарушения стандарта.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...