Как это и и | работает в этом примере C? - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь этот пример, и я не понимаю, как эти значения появляются. Как выполняется побитовая операция, если значения не инициализированы?

int main() {
  int a, b, c, d;
  d = a % b;
  c = a | b;
  printf("OR: %d", c);
  printf("AND: %d", d);
  return 0;
}

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Не зная, каким компилятором вы пользуетесь, трудно понять, каким будет результат, но, скорее всего, он будет равен 0 или некоторым

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

Я использовал компилятор ARM, поскольку ЦП ARM - это компьютер с сокращенным набором инструкций (RISC), и его ассемблерный код немного легче читать.

Чтобы скомпилировать ваш код, я выполнил инструкцию

arm-linux-gnueabi-gcc-7 -S -O0 -fverbose-asm  main.c

, который сгенерировал файл main.s. -S вызывает генерацию кода сборки. -fverbose-asm добавляет код Sorce в качестве комментариев в коде Assmenly. И -O0 не позволяет этому компилятору оптимизировать код до чего-то более сложного для чтения.

Ваш код ИЛИ генерирует:

@ main.c:7:  c = a | b;
        ldr     r2, [fp, #-8]   @ tmp115, a
        ldr     r3, [fp, #-12]  @ tmp116, b
        orr     r3, r2, r3      @ tmp114, tmp115, tmp116
        str     r3, [fp, #-16]  @ tmp114, c
@ main.c:8:  printf("OR: %d\n",c);
        ldr     r1, [fp, #-16]  @, c
        ldr     r3, .L3+4       @ tmp117,
.LPIC1:
        add     r3, pc, r3      @ tmp117, tmp117
        mov     r0, r3  @, tmp117
        bl      printf(PLT)     @

Ваш код AND (исправленный заменой % на &) создает:

@ main.c:9:  d = a & b;
        ldr     r2, [fp, #-8]   @ tmp119, a
        ldr     r3, [fp, #-12]  @ tmp120, b
        and     r3, r3, r2      @ tmp118, tmp120, tmp119
        str     r3, [fp, #-20]  @ tmp118, d
@ main.c:10:  printf("AND: %d\n",d);
        ldr     r1, [fp, #-20]  @, d
        ldr     r3, .L3+8       @ tmp121,
.LPIC2:
        add     r3, pc, r3      @ tmp121, tmp121
        mov     r0, r3  @, tmp121
        bl      printf(PLT)     @

Чтобы ответить на ваш вопрос, не инициализация целых чисел a и b не приводит к изменению кода. Сгенерированный код сборки будет использовать то, что когда-либо находится в памяти, на которую указывает указатель кадра (fp) минус 8 байт и fp минус 12 байт. Если целые числа a и b не установлены на определенное значение, то в зависимости от компилятора вы получите случайное значение или с некоторыми компиляторами вы всегда можете получить нулевое значение.

ПРИМЕЧАНИЕ. Вероятно, ваш компилятор C может генерировать код сборки. Скорее всего, выходные данные будут в сборочном коде i386 или X86, но вы должны быть в состоянии использовать его, чтобы увидеть, как изменение вашего кода изменяет код, сгенерированный вашим компилятором.

Вот пример программы, которая показывает (по крайней мере, с gcc), как не установка значения по умолчанию может привести к побочным эффектам. Здесь значения, передаваемые одной подпрограмме, влияют на другую.

#include <stdio.h>

int first(int x, int y)
{
    int a, b, c, d;

    a = x;
    b = y;
}

int second()
{
    int a,b,c,d;
    c = a | b;
    printf("OR: %d\n",c);
    d = a & b;
    printf("AND: %d\n",d);
}

int main()
{
    first(5, 3);
    second();
    first(7, 5);
    second();
    return 0;
}

Выходное значение

OR: 7
AND: 1

для 5 и 3 и

OR: 7
AND: 5

для 7 и 5.

0 голосов
/ 09 января 2019

Неинициализированная переменная содержит значение мусора, и его использование может стать неопределенным поведением . Быть напуганным .

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

Кстати, вы должны включить все предупреждения и отладочную информацию при компиляции. С GCC , используйте gcc -Wall -Wextra -g. Ваш исходный код, вероятно, вызовет некоторое предупреждение. Я рекомендую всегда инициализировать автоматические переменные (возможно, оптимизирующий компилятор выяснит, что инициализация бесполезна, а затем пропустит ее, согласно как если бы правило ; но вы уверены, что переменная имеет какое-то общеизвестное значение).

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

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