Есть ли способ обратиться к одному биту в C?

Привет я сделал некоторые исследования на бит адресации микроконтроллеров. Единственный, который столкнулся на моем пути, - это Intel MCS-51 (страница wiki), который по-прежнему используется очень часто сегодня... Мне было интересно, можете ли вы напрямую обратиться к биту в C, например, на Регион СФР архитектура памяти wiki 8051.

биты, к которым я обращаюсь в SFR, они адресованы непосредственно, или это побитовая операция в битовом поле, которое адресовано байтом или это что-то совсем другое?

конкретно, здесь: проверьте, установлен ли один бит, похоже, что бит напрямую управляется MOV, мне интересно, возможно ли это в C (с расширениями) или это выглядит только как побитовая операция, но в фоновом режиме есть некоторые компиляторы, которые используют только байты?

в качестве последующего вопроса, есть ли какие-либо бит адресуемые современные процессоры?

6 ответов


это не редкость. Например, SDCC (Small Device C Compiler)-популярный компилятор для MCS-51. Вы найдете инструкция тут. Наиболее актуальным разделом является 3.4.1, в нем описаны расширения языка для MCS-51:

3.4.1.6 __бит

Это тип данных и спецификатор класса хранения. Когда переменная объявленный как бит, он выделяется в бит адресуемой памяти 8051, например:

 __bit test_bit;

запись 1 в эту переменную генерирует код сборки:

 D2*00 setb _test_bit

адресуемая память бита состоит из 128 битов которые расположены от От 0x20 до 0x2f в памяти данных. Помимо этого 8051 конкретного класса хранения большинство архитектур поддерживают ANSI-C bitfields4. В соответствии с ISO/IEC 9899 бит и битовые поля без явного подписанного модификатора реализуются как неподписанные.


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

вот пример программы. Он объявляет битовое поле с объединением с обычным типом того же размера.

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct 
    {
        union
        {
            struct {
                int bit0:1;
                int bit1:1;
                int bit2:1;
                int bit3:1;
                int bit4:1;
                int bit5:1;
                int bit6:1;
                int bit7:1;
            };
            unsigned char byte;
        };
    } EigthBits;

    EigthBits b;

    b.byte = 0;
    printf("Will be 0 ==> %d\n", b.byte);

    b.bit4 = 1;
    printf("Will be 16 ==> %d\n", b.byte);
}

напечатает этот вывод:

    Will be 0 ==> 0
    Will be 16 ==> 16

полезно, например, установить значения для отдельного бита в регистре управления. Вы можете установить больше битов (например,int two_bits:2;), чтобы удовлетворить ваши по необходимости.


В C вы обычно читаете один байт, а затем маскируете бит, который хотите, но некоторые компиляторы процессора предварительно определяют регистры или даже отдельные биты для вас. Например, руководство пользователя Keil Cx51 определяет немного и sfr типы данных.

можно использовать sfr типа такой:

sfr P0 = 0x80;    // Port 0 is accessed at address 80h.
P0 = 0x20;        // Write 20h to Port 0.

чтобы использовать метод byte-at-a-time, вы должны сделать что-то вроде этого:

#define SFR (* (unsigned char *) 0x80)  // Address of SFR is 0x80.

#define BIT0 0x01  // LSB of any byte
#define BIT1 0x02
#define BIT2 0x04
. . .
#define BIT7 0x80  // MSB of any byte

// Read BIT1 of SFR. sfrBit1 is 1 if BIT1 is set, 0 if not.
unsigned char sfrBit1 = SFR & BIT1  ?  1 : 0;

// Set BIT0 of SFR.
SFR |= BIT0;

// Clear BIT2 of SFR.
SFR &= ~BIT2;

для удобства вы можете определить макросы утилиты для установить и очистить отдельные биты:

#define SET(reg, bit) reg |=  (1 << bit)  // Sets a bit in reg.
#define CLR(reg, bit) reg &= ~(1 << bit)  // Clears a bit in reg.

SET(SFR, 1); // Set BIT1 
CLR(SFR, 2); // Clear BIT2

процессор 8051 определяет несколько инструкций для адреса одного бита, чтобы очистить до 0, установить в 1 или проверить значение, за которым следует условная ветвь, чтобы обойти следующий код, если бит был установлен или очищен.

эти инструкции очень эффективны, используя только 2 байта. Первый байт определяет инструкцию, а второй-операнд, который определяет, какой бит использовать, из 256 бит.

первые 128 бит ссылаются на 16 байтов SFR (биты 0 до 7 на адрес 0x80 для P0, бит 8 до 15 для SFR на addreess 0x88 для P1, etc до бита 120 до 127 для SFR 0xF8).

следующие 128 бит, как описано выше Хансом Пасантом, ссылаются на 16 байтов внутренней ОЗУ между 0x20 и 0x2F.

8051 фактически прочитал весь байт, тест, установил или очистил указанный бит и записал все 8 бит назад в то же место (за исключением теста). Помимо эффективности, эти инструкции также не изменяют регистры, такие как R0-R7, гидроаккумулятор и т. д.

компилятор C может легко принять более 128 "__битных" переменных и заменить эффективный код ассемблера, упомянутый выше, классическими бинарными маскирующими операциями, описанными большинством людей. Однако самым простым решением, реализованным компилятором Keil, является объявление ошибки при использовании более 128-битных переменных.

есть некоторые DSP и графические процессоры, которые могут обращаться к указанному количеству бит. Это может быть очень полезно при написании эффективный алгоритм сжатия, некоторая процедура рисования и т. д. Например, TMS34010 из Texas Instruments может определить две группы регистров, используя разное количество битов для каждого доступа к памяти. Цикл может читать, например, 3 бита за раз, используя регистр из первой группы, и записывать 11 бит, используя регистр во второй группе. Внутри контроллер памяти все еще считывал 16 бит и записывал обратно 16 бит и изменял только указанное количество бит внутри каждого 16 бит слова. Все операции памяти ссылаются на бит, а не на слово. Например, счетчик программы увеличивается на 16 при выполнении каждой инструкции. Аппаратное обеспечение создало бы исключение, если бы для более низких битов было бы ненулевым, но для выполнения некоторого типа запутывания было бы легко для Texas Instrument сделать чип, который согласился бы прочитать код операции с некоторым смещением бита.

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


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

в стандарте ISO C наименьшей адресуемой единицей хранения является байт, представленный типами символов.

доступ к битам (даже членам битового поля структур) осуществляется путем доступа ко всей ячейке окружающих битов.

Если процессор может адресовать bits, возможно, один из способов добраться до этого-через встроенный язык сборки компилятора C, если у него есть такая вещь. Или внешне связанные процедуры ассемблера.


это зависит от того, что вы подразумеваете под "способом обращения". Нет никаких проблем в написании некоторых set_bit(address, bit, value), get_bit(address, bit, value) функции, которые будут выполнять такие действия. Однако get_bit вернуться char по крайней мере, это байт.

ограничение байта адресуя приходит естественно от оборудования, которое большинств современный компьютер использует. Это очень похоже на 512-байтовый сектор жесткого диска, который является минимальной операцией ввода-вывода для чтения или записи. Это, однако, не мешает вам писать одиночные байты и биты к нему.