2014-10-31 4 views
1

Вот пример:Как C хранит отрицательные числа в подписанных целых числах без знака?

#include <stdio.h> 

int main() 
{ 
    int x=35; 
    int y=-35; 
    unsigned int z=35; 
    unsigned int p=-35; 
    signed int q=-35; 
    printf("Int(35d)=%d\n\ 
Int(-35d)=%d\n\ 
UInt(35u)=%u\n\ 
UInt(-35u)=%u\n\ 
UInt(-35d)=%d\n\ 
SInt(-35u)=%u\n",x,y,z,p,p,q); 

    return 0; 
} 

Выход:

Int(35d)=35 
Int(-35d)=-35 
UInt(35u)=35 
UInt(-35u)=4294967261 
UInt(-35d)=-35 
SInt(-35u)=4294967261 

ли это важно, если я объявляю значение, как знаком или без знака Int? Потому что C на самом деле заботится только о том, как я читаю значение из памяти. Пожалуйста, помогите мне понять это, и я надеюсь, что вы докажете, что я неправ.

+0

Это не C, а конкретный компьютер, на котором хранятся номера. Стандарт C99 только документирует набор свойств их поведения. –

ответ

3

Действительно ли это, если я объявляю значение как подписанное или неподписанное int?

Да.

Например, взгляните на

#include <stdio.h> 

int main() 
{ 
    int a = -4; 
    int b = -3; 
    unsigned int c = -4; 
    unsigned int d = -3; 
    printf("%f\n%f\n%f\n%f\n", 1.0 * a/b, 1.0 * c/d, 1.0*a/d, 1.*c/b); 
} 

и его выход

1.333333 
1.000000 
-0.000000 
-1431655764.000000 

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

+0

Есть ли способ прочитать двоичное представление, чтобы увидеть, что именно происходит там? – A6SE

+0

@ A6Tech: Да, прочитайте его как 'unsigned char'. – Deduplicator

+0

@Deduplicator Спасибо, вы знаете спецификатор для unsigned char? Обычно я использую c для символов, но я не уверен, как читать как unsigned. – A6SE

4

unsigned int и signed int занимают одинаковое количество байтов в памяти. Они могут хранить одинаковые значения байтов. Однако данные будут обрабатываться по-разному в зависимости от того, подписаны они или нет.

См. http://en.wikipedia.org/wiki/Two%27s_complement для объяснения наиболее распространенного способа представления целочисленных значений.

Поскольку вы можете придать тип на C, вы можете эффективно заставить компилятор обрабатывать unsigned int как подписанный int и наоборот, но будьте осторожны, что это не значит, что он будет делать то, что вы думаете, или что представление будет правильным. (Переполнение знакового целого вызывает неопределенное поведение в C).

(Как было отмечено в комментариях, есть и другие способы представления чисел, чем дополнения до двух, однако двоичное дополнение является наиболее распространенным способом на настольных машинах.)

+0

Вот как C может это сделать ... *** некоторое время ***. Вводящий в заблуждение и неполный. – Deduplicator

+0

Дело просто в том, что это не так, как C, но как C иногда может это сделать. В других случаях это по-разному влияет на, возможно, другой результат. – Deduplicator

+1

Компьютер может иметь дополнение к целым числам и иметь стандартную реализацию C99. Но это очень необычно! И реализация C99 даже не требует какого-либо компьютера (вы могли бы использовать кучу человеческих рабов, но это было бы неэтично, неэффективно, хрупко!). –

-1

Самая фундаментальная вещь, тип переменной определяет путь он хранится (то есть - считывается и записывается в) в памяти и как интерпретируются биты, поэтому ваше утверждение можно считать «действительным».

Вы также можете просмотреть проблему, используя преобразования. Когда вы сохраняете подписанное и отрицательное значение в неподписанной переменной, оно преобразуется в unsigned. Так получилось, что это преобразование обратимо, поэтому подписанный -35 преобразуется в unsigned 4294967261, который - когда вы его запрашиваете - может быть преобразован в подписанный -35. Вот как работает кодировка дополнения 2 (см. Ссылку в другом ответе).

+0

Итак, в чем заключается необходимость в unsigned int, когда я могу хранить все числа в int и читать их как подписанные или неподписанные по моей воле? : D – A6SE

+0

@ A6Tech Как вы узнаете, что выбрать, имеет ли он 2 значения? – Jite

+0

Вы также можете использовать необработанную память ('void *') с необработанными буферами и приведениями типа везде, но это C, а не ассемблер (; –

1
#include <stdio.h> 

int main(){ 
    int x = 35, y = -35; 
    unsigned int z = 35, p = -35; 
    signed int q = -35; 

    printf("x=%d\tx=%u\ty=%d\ty=%u\tz=%d\tz=%u\tp=%d\tp=%u\tq=%d\tq=%u\t",x,x,y,y,z,z,p,p,q,q); 
} 

результат: х = 35 х = 35 у = -35 у = 4294967261 г = 35 г = 35 р = -35 р = 4294967261 д = -35 д = 4294967261

int number store не отличается, он хранится в стиле дополнения в памяти,

Я могу использовать 0X ... 35 в 0X00000023 и -35 в 0Xffffffdd, это не значит, что вы используете sigend или unsigend. он выводится только с разных сийтов.% D и% u не отличаются от положительных, но отрицательная первая позиция является значком, если вы выставляете с% u равно 0xffffffdd равным 4294967261, но% d 0Xffffffdd может быть - 0X00000023 равным -35.

+0

Вот почему я спросил, для чего используется unsigned int. Но пример glglgl показывает, что чтение тех же двоичных чисел, что и float, дает разные арифметические результаты. Но я не понимаю, как ... – A6SE

+0

В примере glglgl показано разделение чисел с поплавком, этот пример не является int-делением, номер хранит память с IEEE 754 (http://en.wikipedia.org/wiki/IEEE_754- 1985), а поплавковое подразделение немного сложное, вы можете увидеть некоторые сведения, а также отличия знака или unsign. –

2

Representation of signed integers относится к базовой платформе, а не самому языку C. Определение языка в основном является агностическим в отношении подписанных целочисленных представлений. Two's complement, вероятно, является наиболее распространенным, но существуют другие представления, такие как one's complement и signed magnitude.

в двухдневной в системе комплемента, вы инвертировать значение путем инвертирования битов и добавления 1. Для того, чтобы получить от 5 до -5, вы могли бы сделать:

5 == 0101 => 1010 + 1 == 1011 == -5 

Чтобы перейти от -5 обратно 5, вы следовать той же процедуре:

-5 == 1011 => 0100 + 1 == 0101 == 5 

ли это на самом деле имеет значения, если я объявляю значение, как знаком или без знака Int?

Да, по следующим причинам:

  1. Это влияет на значения, которые вы можете представить: целые числа без знака могут представлять значение от 0 до 2N-1, в то время как целые числа могут представлять значения между -2N-1 и 2N-1-1 (два-х дополнение).

  2. Переполнение отлично определено для целых без знака; UINT_MAX + 1 «обернется» обратно до 0. Переполнение равно , а не, четко заданное для целых чисел со знаком, и INT_MAX + 1может «обернуть» до INT_MIN, а может и нет.

  3. Из-за 1 и 2 он влияет на арифметические результаты, особенно если вы смешиваете подписанные и неподписанные переменные в одном выражении (в этом случае результат может быть нечетким, если есть переполнение).