2012-06-24 8 views
0

Можно создать дубликат:
Unsigned long with negative value
Assigning negative numbers to an unsigned int?Беззнаковые и подписанные целые числа в C

#include<stdio.h> 

int main() 
{ 
    struct a 
    { 
     unsigned int i:3; 
     int c:3; 
    }s; 
    s.i=5; 
    s.c=5; 

    printf("s.i=%d\n",s.i); 
    printf("s.c=%u\n",s.c); 
    unsigned int x = -1; 
    printf(" x = %d", x); 
    return 0; 
} 

В этом выходы:

s.i=5 
s.c=4294967293 
x=-1 

Я не понимаю, как вывод «x» и «sc» (sc может хранить только 3 бита, но на выходе он дает очень большое значение). «X» объявляется как unsigned, поэтому биты, хранящиеся в x, являются 1111111 ....... и выход x должен быть большим значением вместо -1. 1-й вывод printf() дает результат как ожидалось Я использую компилятор devC++.

+3

Почему вы не сделали свой код? –

+0

Все ваши аргументы передаются 'printf' как' int ', зависит от вас, чтобы установить соответствующие спецификаторы формата. –

ответ

2

кажется, есть две вещи, идущие на этом, необходимо понимать:

  • printf() спецификаторы преобразования
  • Интегральные конверсии

И еще две вещи й при помощи имеет смысл вашей продукции: продвижение

  • Аргумента для аргументов функции переменного числа
  • дополнения представления
  • двоек

первых, printf() является VARIADIC функции. Он не знает, каковы типы его аргументов (кроме строки формата), поэтому вам нужно использовать спецификаторы преобразования, чтобы рассказать ему, как интерпретировать аргументы. Эти аргументы подвержены «рекламным акциям по умолчанию», так что ваши поля с 3-битными битами повышаются до int с.

Вы используете конверсии спецификатор (%d, %u и %d), которые не соответствуют знаковости ваших данных, так что вы получите неопределенное поведение, которое зависит от того, как данные фактически представлены в памяти.

Во-вторых, стандартные состояния С11:

6.3.1.3Подписанные и целые числа без знака

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

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

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

(Насколько я могу сказать, подробности Уместно было верно, по крайней мере, так как C89.)

Это говорит нам несколько вещей о вашем коде:

  • При присвоении -1unsigned int добавляется UINT_MAX + 1, давая UINT_MAX или 4294967295 для 32-битных целых чисел.

  • При попытке назначить 5 3-разрядному разрядному битовому полю результат будет определяться реализацией.

Таким образом, у вас есть неопределенное и определяемое реализацией поведение, но мы все же можем попытаться разобраться в вашем выходе, просто для удовольствия. Я предполагаю 32-битные целые числа и two's complement.

Ваша система представляет 4294967295, хранящуюся в x, как 11111111 11111111 11111111 11111111. Когда вы сказали printf(), что аргумент, который вы проходили, был подписан, эти же биты интерпретируются как -1, который является результатом, который вы получили.

Для s.c поведение определяется реализацией вы, кажется, получили очень просто: три бита 101 представляющие 5 получил сохранён как есть. Это означает, что с правильным спецификатором преобразования printf() должен показывать s.c как -3.

Ниже приведены значения, вы назначены:

s.i = 101 
s.c = 101 
    x = 11111111 11111111 11111111 11111111 

В 3-битовых значениях повышены до 32-битого левой кнопки дополнения с 0 для беззнакового значения и повторяя знак подписанного значения:

s.i = 00000000 00000000 00000000 00000101 
s.c = 11111111 11111111 11111111 11111101 
    x = 11111111 11111111 11111111 11111111 

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

s.i=5 
s.c=4294967293 
x=-1 

x=-1 предлагает мне, что вы на самом деле используете представление двух дополнений (что было довольно безопасно, в любом случае), а вывод для s.c предполагает, что ваши int s имеют ширину 32 бит.

+1

Его очень хорошее объяснение. У меня есть небольшое сомнение. Если значение sc = 3 (011), то оно будет преобразовано в sc = 00000000 00000000 00000000 00000011 как 32-битное целое. Поскольку sc подписано и его значение 5 (101) указывает на него как отрицательное число, поэтому при преобразовании в 32- битное целое число составляло 1 во всех позициях бит, за исключением последних трех разрядных позиций (в этом случае, поскольку последние три бита будут самими числами). – sourabh912

+0

@ sourabh912 Да, у вас оно есть. Обратите внимание, что 111 ... 101 фактически -3. (Все это предполагает две арифметические операции дополнения, которые являются почти универсальными.) –

+0

Спасибо Джим и Даршан. Одна из вас очень помогла. – sourabh912

4

Выход зависит от подписанности символа формата, а не от подписности декларации. Подумайте об этом: printf не знает, было ли x объявлено int или unsigned int, так как в C. не передается информация о типе. Таким образом, он печатает на основе того, как вы сказали это для печати. % d подписывается, поэтому вы получаете знаковое значение. С s.c это int, поэтому он подписан, но вы печатали его с% u, поэтому он обрабатывается как unsigned.

Что касается си, это без знака, так что 5 может поместиться в его 3 бита, поэтому он передается PRINTF как 5 без знака расширения, поэтому% d (или% и) печатает его как 5.

+0

, если то, что вы сказали, истинно, тогда не должно выводиться printf ("s.i =% d \ n", s.i); – sourabh912

+0

Вы не закончили свою мысль, но я ответил в своем правлении. Там нет «если» об этом - это основной вопрос, понятный всем программистам на С, которые не только начинаются так, как есть. –

+0

Извините, что была проблема с моим подключением к Интернету, поэтому я не мог редактировать свой комментарий. Фактически я спрашивал, что shouldnt вывод printf («s.i =% d \ n», s.i); be -3 (потому что мой спецификатор формата% d и «i» хранится только в 3 битах, поэтому 5 (101) следует рассматривать как отрицательный). – sourabh912

Смежные вопросы