Подтвердить что ты не робот

Почему было создано ключевое слово register?

При чтении Ключевые слова, которые не являются (или, комментарии от другого имени), Herb Sutter Я наткнулся на эти строки:

Правильно, некоторые ключевые слова семантически эквивалентны пробелу, прославленному комментарию.

и

Мы видели, почему язык С++ рассматривает ключевые слова как зарезервированные слова, и мы видели два ключевых слова -auto и register - которые не имеют никакой смысловой разницы для С++-программы. Не используйте их; они все равно просто пробелы, и есть более быстрые способы ввода пробелов.

Если ключевые слова типа auto (возможно, не в С++ 11) и register не имеют значения, то почему они были созданы и использованы?

Если не нужно включать register перед переменной

#include<stdio.h>
int main(){
    register int a = 15;
    printf("%d\n%d\n",&a,a);
    return 0;
}

Почему указанная выше программа сообщает об ошибке?

test_register.c: В функции main:

test_register.c: 4: 2: ошибка: адрес переменной регистра 'запрошенный

Е ( "% d\п% г\п", & а, а);

Следующая программа работает на С++.

#include<iostream>
int main(){
    register int a = 15;
    std::cout<<&a<<'\n'<<a;
    return 0;
}
4b9b3361

Ответ 1

Регистр

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

Объявление идентификатора для объекта с спецификатором класса хранения register предполагает, что доступ к объекту должен быть как можно быстрее. Степень, в которой такие предложения эффективны, определяется реализацией. [сноска 121]

[footnote 121] Реализация может обрабатывать любое объявление register просто как объявление auto. Тем не менее, независимо от того, действительно ли используется адресное хранилище, адрес любой части объекта, объявленного с помощью спецификатора класса хранения register, не может быть вычислен, либо явно (с использованием унарного и оператора as обсуждается в 6.5.3.2) или неявно (путем преобразования имени массива в указатель, как описано в 6.3.2.1). Таким образом, единственными операторами, которые могут быть применены к массиву, объявленному с помощью спецификатора класса хранения register, являются sizeof и _Alignof.

В С++ это просто неиспользуемое зарезервированное ключевое слово, но разумно предположить, что оно хранилось для синтаксической совместимости с кодом C.

авто

В C класс хранения auto определяет переменную автоматического хранения, но обычно не используется, поскольку функционально-локальные переменные auto по умолчанию.

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

Ответ 2

register в C служил в двух целях:

  • Подскажите компилятору, что переменная должна храниться в регистре для производительности. В настоящее время это использование устарело.
  • Запретить программисту использовать переменную таким образом, чтобы предотвратить ее хранение в регистре. Это использование является лишь устаревшей ИМО.

Это похоже на const, который

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

В качестве примера рассмотрим эту упрощенную функцию:

int sum(const int *values, size_t length) {
    register int acc = 0;
    for (size_t i = 0; i < length; ++i) {
        acc += values[i];
    }
    return acc;
}

Программист написал register, чтобы сохранить накопитель со стека, избегая записи памяти каждый раз, когда он обновляется. Если реализация будет изменена на что-то вроде этого:

// Defined in some other translation unit
void add(int *dest, int src);

int sum(const int *values, size_t length) {
    register int acc = 0;
    for (size_t i = 0; i < length; ++i) {
        add(&acc, values[i]);
    }
    return acc;
}

Переменная acc больше не может храниться в регистре, когда его адрес берется для вызова add(), потому что регистры не имеют адреса. Таким образом, компилятор будет отмечать &acc как ошибку, сообщив вам, что вы, вероятно, уничтожили производительность вашего кода, не допустив acc от проживания в регистре.

Это было гораздо более важным в первые дни, когда компиляторы были глупее, а переменные могли жить в одном месте для целой функции. В настоящее время переменная может провести большую часть своей жизни в регистре, перемещаясь в стек только временно, когда его адрес занят. То есть, этот код:

/* Passed by reference for some reason. */
void debug(const int *value);

int sum(const int *values, size_t length) {
    int acc = 0;
    for (size_t i = 0; i < length; ++i) {
        acc += values[i];
    }
    debug(&acc);
    return acc;
}

заставил бы acc жить в стеке для всей функции в старых компиляторах. Современные компиляторы сохраняют acc в регистре до самого вызова debug().

Современный код C обычно не использует ключевое слово register.

Ответ 3

C99 Обоснование предоставляет еще один контекст ключевого слова register:

Обоснование для международного стандарта - Языки программирования - C

§6.7.1 Спецификаторы класса хранения

Поскольку адрес переменной register невозможен, объекты класса хранения register эффективно существуют в пространстве, отличном от других объектов. (Функции занимают еще третье адресное пространство.) Это делает их кандидатами для оптимального размещения, обычной причиной объявления регистров; но это также делает их кандидатами для более агрессивной оптимизации.