Тема: Що це register?

Багато помилок
Я жодного разу не знаю, це автор зовсім тупить або помилка незначна.
А взагалі їх вагон- шістдесят сім помилок та девьять попереджень.
Причому усі зовсім різні.
Ось. void delete(void), list(void);

А, ні, усе, поступово повбирав.  А ось що таке register?

Зкомпілювалося, але що це?  Незрозумію!

#include <stdio.h>
#include <stdlib.h>

#define MAX 100

struct addr {
  char name[30];
  char street[40];
  char city[20];
  char state[3];
  unsigned long int zip;
} addr_list[MAX];

void init_list(void), enter(void);
void Funcdelete(void), list(void);
void load(void), save(void);
int menu_select(void), find_free(void);

int main(void)
{
  char choice;

  init_list(); // инициализация массива структур 
  for(;;) {
    choice = menu_select();
    switch(choice) {
      case 1: enter();
        break;
      case 2: Funcdelete();
        break;
      case 3: list();
        break;
      case 4: save();
        break;
      case 5: load();
        break;
      case 6: exit(0);
    }
  }

  return 0;
}

// Инициализация списка. 
void init_list(void)
{
  register int t;

  for(t=0; t<MAX; ++t) addr_list[t].name[0] = '\0';
}

// Получения значения, выбранного  в меню. 
int menu_select(void)
{
  char s[80];
  int c;

  printf("1. Ввести имя\n");
  printf("2. Удалить имя\n");
  printf("3. Вывести список\n");
  printf("4. Сохранить файл\n");
  printf("5. Загрузить файл\n");
  printf("6. Выход\n");
  do {
    printf("\nВведите номер нужного пункта: ");
    gets(s);
    c = atoi(s);
  } while(c<0 || c>6);
  return c;
}

// Добавление адреса в список. 
void enter(void)
{
  int slot;
  char s[80];

  slot = find_free();

  if(slot==-1) {
    printf("\nСписок заполнен");
    return;
  }

  printf("Введите имя: ");
  gets(addr_list[slot].name);

  printf("Введите улицу: ");
  gets(addr_list[slot].street);

  printf("Введите город: ");
  gets(addr_list[slot].city);

  printf("Введите штат: ");
  gets(addr_list[slot].state);

  printf("Введите почтовый индекс: ");
  gets(s);
  addr_list[slot].zip = strtoul(s, '\0', 10);
}

// Поиск свободной структуры. 
int find_free(void)
{
  register int t;

  for(t=0; addr_list[t].name[0] && t<MAX; ++t) ;

  if(t==MAX) return -1; // свободных структур нет 
  return t;
}

//Удаление адреса. 
void Funcdelete(void)
{
  register int slot;
  char s[80];

  printf("Введите № записи: ");
  gets(s);
  slot = atoi(s);

  if(slot>=0 && slot < MAX)
    addr_list[slot].name[0] = '\0';
}

// Вывод списка на экран. 
void list(void)
{
  register int t;

  for(t=0; t<MAX; ++t) {
    if(addr_list[t].name[0]) {
      printf("%s\n", addr_list[t].name);
      printf("%s\n", addr_list[t].street);
      printf("%s\n", addr_list[t].city);
      printf("%s\n", addr_list[t].state);
      printf("%lu\n\n", addr_list[t].zip);
    }
  }
  printf("\n\n");
}

// Сохранение списка. 
void save(void)
{
  FILE  *fp;
  register int i;

  if((fp=fopen("maillist", "wb"))==NULL) {
    printf("Ошибка при открытии файла.\n");
    return;
  }

  for(i=0; i<MAX; i++)
    if(*addr_list[i].name)
      if(fwrite(&addr_list[i],
         sizeof(struct addr), 1, fp)!=1)
           printf("Ошибка при записи файла.\n");

  fclose(fp);
}

// Загрузить файл. 
void load(void)
{
  FILE  *fp;
  register int i;

  if((fp=fopen("maillist", "rb"))==NULL) {
    printf("Ошибка при открытии файла.\n");
    return;
  }

  init_list();
  for(i=0; i<MAX; i++)
    if(fread(&addr_list[i],
       sizeof(struct addr), 1, fp)!=1) {
         if(feof(fp)) break;
         printf("Ошибка при чтении файла.\n");
    }

  fclose(fp);
}

//--------------------------------------------------------------------------------

2

Re: Що це register?

Специфікатори класу пам'яті
там почитати за register
вказується що змінна повина занестись в регістр, для швидкої роботи, але часто цією примхою компілятори нехтують, бо є на це ряд причин в архітектурі intel i amd

- Поганому трояну фаєрвол заважає
- Ніколи не програмуйте та не пийте пиво
Якщо ви з першого разу написали програму, в якій немає жодної помилки, повідомте про це системного програмісту: він виправить помилки в компіляторі
Подякували: Дмитро-Чебурашка1

Re: Що це register?

Використання volatile, extern, register, auto, mutable в C ++ (огляд)
Стаття

автор  tellurian tellurian 

У мові C ++ є кваліфікатори і специфікатори, які у зв'язку з їх не дуже частим використанням можуть викликати замішання у недосвідчених і початківців. У даному короткому нарисі я збираюся пролити світло на дану тему.

Почнемо з кваліфікатора volatile
Якщо підходити формально то кваліфікатор volatile інформує компілятор що змінна може бути змінена не явним способом тобто без явного без явного використання оператора присвоєння.  І що ж це означає на практиці?  Справа в тому, що як правило компілятори автоматично застосовують оптимізацію, припускаючи що значення змінної залишається постійним, якщо воно не вказано з лівого боку від оператора присвоєння. Т.е. Тобто  якщо змінна не змінюється, то і немає потреби перевіряти її при кожному зверненні.

Приклад:

 bool exit = true; 
 while( exit )
 { }; 

В даному випадку значення змінної exit буде прочитано тільки одого разу.  На перший погляд в цьому немає нічого страшного.  Однак, якщо зміст змінно exit може змінювати не тільки код поточного потоку, але припустимо інший потік (опустимо зараз питання атомарности операції) або взагалі якесь зовнішні пристрій, то ми можемо отримати нескінченний цикл яким він по нашому задуму бути не повинен.

Але якщо ми перед оголошенням змінної поставимо кваліфікатор volatile, то змінна буде зчитуватися при кожній перевірці.

Приклад:

volatile bool exit = true; while( exit ) { };  Наведу більш життєвий приклад.  Припустимо є необхідність роботи з зовнішньому пристроєм через деякий порт.  Нам потрібно записати в порт послідовність з трьох нулів.

 unsigned char* pControl = 0xff24 ;
 *pControl = 0 ; 
 *pControl = 0 ; 
 *pControl = 0 ; 

Після оптимізації замість трьох нулів буде записаний лише один.
Більше того після оптимізації прочитати що або з порту буде не реально тому  зміни змінної відбуватимуться у зовнішньому середовищі.

Герберт Шилдт наводить такий приклад: Наприклад, адреса глобальної змінної можна передати таймером операційної системи і використовувати його для відліку часу.  У цьому випадку вміст змінної змінюється без явного виконання будь-якого оператора присвоєння.

Чисто теоретично якщо бути стовідсотково впевненим у атомарности операції, то можна використовувати кваліфікатор volatile для взаємодію змінної між потоками без використання додаткових об'єктів синхронізації таких як м'ютекси, але оскільки таку впевненість може дати хіба що char, то застосовувати volatile в цих цілях буде не коректним.

Застосовувати volatile на додаток до м'ютексів немає необхідності, хоча на цю тему зламано багато списів, але прикладів реальних компіляторів і ОС, де м'ютексів мало, мені не зустрічалося.  До речі, функції-члени теж можуть оголошуватися зі словом volatile:

 class A { public: void foo() volatile; } 

  В даному випадку всередині foo () покажчик this так само має атрибут volatile.

Специфікатор extern
У мовах з \ с ++ існують внутрішні зв'язки, зовнішні зв'язки і відсутність зв'язків.  Глобальні змінні мають зовнішні зв'язки і це дозволяє отримати доступ до них з будь-якої частини програми.  Якщо до глобальних змінних додати специфікатор static, то глобальні змінні втратять зовнішні зв'язки і будуть мати тільки внутрішні зв'язки, тобто будуть доступні тільки знутри файлу, в якому вони були описані. будуть доступні тільки всередині файлу, в якому вони були описані.  Локальні змінні не мають зв'язків і тому доступні тільки зсередини блоку де вони були описані.

Специфікатор extern вказує, що змінна володіє зовнішніми зв'язками.  Справа в тому, що треба розрізняти визначення та оголошення.  Оголошення вказує ім'я об'єкта та його тип, то де як визначення виділяє під об'єкт пам'ять.  Таким чином можна зробити кілька оголошень об'єкта і тільки одне визначення. У більшості випадків, визначення та оголошення збігаються.  Специфікатор extern дозволяє оголосити змінну без її визначення т.е без виділення пам'яті.  Використовуючи специфікатор extern можна шляхом оголошення звернутися до змінної, визначеної в іншому місці.  Наприклад, можна визначити всі глобальні змінні в одному файлі, а в інших файлах отримувати до них доступ через оголошення зі специфікатором extern.

Специфікатор register
Спочатку це специфікатор застосовувавсь тільки до змінних типу char і int, але тепер його можна застосовувати до змінних будь-якого типу.  Даний специфікатор вказує компілятору зберігати значення змінної не в пам'яті, а в регістрі процесора. Інше трактування специфікатора register таке що він служить підказкою компілятору, що даний об'єкт використовується дуже інтенсивно.  Зрозуміло в регістрах зможуть поміститися тільки дані дуже обмеженого обсягу, такі як int і char, а боле великі об'єкти в регістри не помістяться, але отримають більш високий пріоритет обробки.  Треба враховувати, що register це рекомендація така ж як inline і компілятор може просто ігнорувати специфікатор register і обробляти змінну як звичайно.

Так само зауважу, що специфікатор register можна застосовувати тільки до локальних змінних і до формальних параметрів.

 bool foo(register char ch) 
 { 
   register bool bRes; 
   return bRes; 

}  Компілятор автоматично перетворює зайві реєстрові змінні в звичайні, тому немає сенсу в підрахунку кількості реєстрових змінних що забезпечує машино-незалежність.

Ключове слово auto
Долю цього ключового слово можна порівняти з goto: з одного боку - у мові є, з іншого - його не використовують.  Але у випадку з auto все простіше.  Хоча його і можна використовувати для оголошення локальних змінних, але сенсу в цьому немає, тому що всі локальні змінні за замовчуванням вважаються автоматичними.  Тому на практиці це ключове слово не використовується.  Є думка що ключове слово auto включили в мову С для сумісності з мовою B ну а потім воно перекочувало і в С ++

Ключове слово mutable

Іноді є необхідність змінити якийсь об'єкт усередині класу, гарантуючи недоторканність інших елементів.  Недоторканність можна гарантувати за допомогою const, проте const забороняє зміну всього.

 class Exm 
 { 
 int a; 
 int b; 
           public: 
 int getA() const 
 { 
       return a; // все правильно 
 } 
 int setA(int i) const
 { 
       a = i;// помилка доступу
 }
 }

  Допомогти в цьому випадку може визначення змінної а з ключовим словом mutable.  Внесемо виправлення в наведений трохи вище приклад:

 class Exm 
 { 
 mutable int a; // додали в оголошення ключове слово mutable 
                // що дозволяють ігнорувати модифікатор const 
                // по відношенню до цієї змінної   
         int b; 
            public: 
         int getA() const 
          { 
              return a; // все правильно 
          } 
         int setA(int i) const 
         { 
              a = i;// тепер все правильно. Ми можемо змінювати змінну а 
              b = i; // Помилка! Змінна b по колишньому не доступна для змін. 
         } 
 } ------------ ------------

Олександр Бабашов (tellurian)

Подякували: koala1