LINUX.ORG.RU

[C] (j>1 && j<-1) равно true


0

1
#include <stdio.h>

int main()
{
    unsigned j = 12;
    printf("j > -1: %i\n", j > -1);
    printf("j < -1: %i\n", j < -1);
    printf("j >  1: %i\n", j > 1);
}
j > -1: 0
j < -1: 1
j >  1: 1

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

Я сначала было подумал, что это из-за представления unsigned. Но после увеличения j на INT_MAX результат не поменялся.

★★★★★

Я сначала было подумал, что это из-за представления unsigned

Правильно подумал. Подумай еще, что такое -1, приведенное к unsigned.

unsigned ★★★ ()

Потому что -1 приводится к unsigned

madcore ★★★★★ ()

> Я сначала было подумал, что это из-за представления unsigned.

А теперь подумай, чему будет равен -1 после приведения к unsigned.

geekless ★★ ()
Ответ на: комментарий от Eddy_Em

И правда. Блин.

    j = (unsigned)(-1);
    printf("%u\n", j);
    j = (unsigned)(INT_MAX);
    printf("%u\n", j);

Всё прояснилось.

Кстати, почему-то gcc -Wall не ругается на фигню из топика, а g++ -Wall ругается.

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Obey-Kun
#include <stdio.h>
#include <limits.h>

int main()
{
    printf("%u\n", (unsigned)(-1));
    printf("%u\n", (unsigned)(-10));
    printf("%u\n", (unsigned)(-10000));
    printf("%u\n", INT_MAX);
    printf("%u\n", UINT_MAX);
}
Obey-Kun ★★★★★ ()

О! Я тоже на это наступал, пытаясь сравнивать пойнтер (возврат mmap) и -1 ;-)

Там второй операнд случаем не к типу первого приводится?

AIv ★★★★★ ()
Ответ на: комментарий от Obey-Kun

Так а чего тут разгадывать, и так все понятно... фишка в расположении бита, определяющего знак;-)

AIv ★★★★★ ()
Ответ на: комментарий от Led

> За подобный быдлокод руки отрывать нужно

Только ради эксперимента. Сам так никогда не делаю.

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Eddy_Em

> Ага, хотя казалось бы, что (unsigned)(-1) должен быть равен INT_MAX+1.

Вот-вот, я тоже так думал.

Obey-Kun ★★★★★ ()
Ответ на: комментарий от PayableOnDeath

Да я понимаю всё это, вопрос был теоретический и уже решился.

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Eddy_Em

>Ага, хотя казалось бы, что (unsigned)(-1) должен быть равен INT_MAX+1.

это с какой логики? ещё «со счётных палочек» 0 - 1 = [F]

yyk ★★★★★ ()
Ответ на: комментарий от yyk

С такой логики, что -1 => устанавливаем в 1 знаковый бит + устанавливаем число в 1, получаем 1xxx1, т.е. INT_MAX + 2. Упс. Даже не +1, а +2...

Ну, в общем, вроде бы популярное заблуждение. Правда, при таком идиотском представлении отрицательных чисел арифметические операции пришлось бы делать «задом наперед», т.е. вместо сложения вычитать, а вместо вычитания - складывать.. В общем, уйма геморроя была бы.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

>Ну, в общем, вроде бы популярное заблуждение.

я бы сказал «популярное незнание» :)

Правда, при таком идиотском представлении отрицательных чисел арифметические операции пришлось бы делать «задом наперед»


это очень мягко сказано...

yyk ★★★★★ ()
Ответ на: комментарий от Led

unsigned j

j > -1

За подобный быдлокод руки отрывать нужно

Led искренне верит что где то есть формат отличный от «дополнение до двух» как то «знак величина» «дополнение до единицы» для представления знаковых и поэтому считает это быдлокодом

anonymous ()

Вот и выросло поколение...

yaws ()

Кажется, тут уже изжевали вдоль и поперек (нечитал), но:

Но в чём глубинный смысл результата?

В приведении типов.
Битовое представление целочисленной знаковой -1 = строка единиц, которая для беззнакового целого является максимальным представимым числом.
Соответсвенно, компилато привел тип константы -1 к типу переменной (и ругнулся), и в результате имеем то что имеем.



yaws ()
Ответ на: комментарий от Obey-Kun

Ругается:

предупреждение: control reaches end of non-void function
А с -Werror вообще компилировать откажется. А ключик -Werror лучше никогда не отключать!

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

> предупреждение: control reaches end of non-void function

А у меня не ругается. Потому что по C99 в main не надо ретурнить 0, оно само сретурнит, если достигнет }.

gcc -Wall --std=c99

Obey-Kun ★★★★★ ()
Ответ на: комментарий от unsigned

Про ключик -W я не знал (мануал по gcc слишком большой, чтобы его целиком читать :) ). Добавлю в makefile по умолчанию.

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Obey-Kun

я так понял, это вообще _все_ вэрнинги?

Дополнительные предупреждения, т. е. нужны и -Wall и -W. Есть еще куча -W*, которые можно только по отдельности включить, если очень хочется. Ман в курсе )

unsigned ★★★ ()
Ответ на: комментарий от akk
char *pc = 0, *qc = 0;
pc += -1;
qc += 0xfffffffe;
if (pc > qc)
    puts("true");

Если за это не убивать, то за что убивать?

ну если int и размер указателя имеют одинаковый размер 32 бита и если используется дополнение до двух то вполне ожидаемое поведение

anonymous ()
Ответ на: комментарий от anonymous

Во первых, сравнение двух произвольных указателей — это UB. Во-вторых, вы уверены, что при *pc = 0, *qc = 0 эти указатели будут инициализированы одним и тем же физическим адресом?

akk ★★★★★ ()
Ответ на: комментарий от akk

UB в сравнении двух указателей нет пусть они хоть в космос указывают компилятор про это не знает и обязан сгенерить корректный код для сравнения что он и делает другой вопрос что потом с этими указателями делать но это уже другая история а про физический адрес я не понял что Вы имели ввиду ? он обязан обнулить переменные/регистры и потом инкрементировать да и какая разница что в указателе пока нет обращения по нему чтоб достать что то вот мусор в указателе UB ? да пофик если мы не обращаемся по этому указателю никуда это не более чем обычное число/переменная/регистр такое же как int попробуй найди 10 отличий

anonymous ()

Дополнительная арифметика - тайное знание! Если все этим проникнутся, у каждого лорчанина будет гарантирована занятость!

Xenesz ★★★★ ()

За подобный быдлокод руки отрывать нужно

Верно.

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("long long\n");
    {
        unsigned long long j = 12;
        signed long long m = -1;
        signed long long n = 1;
        printf("12 > -1: %i\n", j > m);
        printf("12 < -1: %i\n", j < m);
        printf("12 >  1: %i\n", j > n);
    }
    printf("long\n");
    {
        unsigned long j = 12;
        signed long m = -1;
        signed long n = 1;
        printf("12 > -1: %i\n", j > m);
        printf("12 < -1: %i\n", j < m);
        printf("12 >  1: %i\n", j > n);
    }
    printf("int\n");
    {
        unsigned int j = 12;
        signed int m = -1;
        signed int n = 1;
        printf("12 > -1: %i\n", j > m);
        printf("12 < -1: %i\n", j < m);
        printf("12 >  1: %i\n", j > n);
    }
    printf("short\n");
    {
        unsigned short j = 12;
        signed short m = -1;
        signed short n = 1;
        printf("12 > -1: %i\n", j > m);
        printf("12 < -1: %i\n", j < m);
        printf("12 >  1: %i\n", j > n);
    }
    printf("char\n");
    {
        unsigned char j = 12;
        signed char m = -1;
        signed char n = 1;
        printf("12 > -1: %i\n", j > m);
        printf("12 < -1: %i\n", j < m);
        printf("12 >  1: %i\n", j > n);
    }
    return 0;
}

Результат

long long
12 > -1: 0
12 < -1: 1
12 >  1: 1
long
12 > -1: 0
12 < -1: 1
12 >  1: 1
int
12 > -1: 0
12 < -1: 1
12 >  1: 1
short
12 > -1: 1
12 < -1: 0
12 >  1: 1
char
12 > -1: 1
12 < -1: 0
12 >  1: 1

Вывод: результат сравнения зависит от типа.

Т.к. для сравнения типов меньше int, компилятор сначала приводит операнды к int, а потом уже сравнивает. Если тип >= int, то операнды приводятся к беззнаковому типу, т.к. беззнаковый тип имеет бОльший диапазон значений.

Поэтому warning о signed/unsigned mismatch - скорее всего сигнализирует об ошибке в (быдло) коде.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.