Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.06.2013, 18:46   #1
Aspirisha
Пользователь
 
Регистрация: 12.11.2012
Сообщений: 20
По умолчанию Локальные переменные и стек

Препод уже который раз делает отворот поворот по одной и той же причине: не могу адекватно объяснить когда создаются временные переменные при вызове функции void f(const char &c){} со следующими параметрами
f('1');
f(1);
f(2323);
f(c1); // c1 объявлена как char c1
f(c2); // c2 объявлена как unsigned char c2
f(c3); // c3 объявлена как signed char c3

сначала я подумал что временные переменные создаются только когда вызов от lvalue. Неверно. Затем предположил, что всегда кроме того случая когда тип ссылки и тип входного параметра полностью совпадают, появится временная переменная - тоже мимо. Хотя это как раз уже странно - вроде Стивен Прата пишет что именно так. Отчаявшись, написал программку тестер - и получил вообще неожиданный результат! Во всех случаях почему-то выделяется 4 байта. Если подумать, что это связано со смещением - меняем везде слово char на long long - тот же эффект. Как такое вообще объяснить? Может дело в том, что я не учитываю смещение stack segment? Но его почему то не считать
Код теста:
Код:
#include <iostream>

using namespace std;
int stackGlob = 0;
int stackProg = 0;
int stackSegGlob = 0;
int stackSegProg = 0;
int delta = 0;
#define STD_BIAS 212

void f(const long long &c)
{
  //int i;
  _asm mov stackProg, esp;
  delta = stackGlob - stackProg;
  cout << c << " stack used: " << (delta - STD_BIAS) << endl;
}

int main(void)
{
  char c1 = 'a';
  unsigned char c2 = 'b';
  signed char c3 = 34;

  long long d1 = 1;
  unsigned long long d2 = 34.4;
  signed long long d3 = -34.4;
  _asm 
  {
    mov stackGlob, esp;
    //mov stackSegGlob, ess;
  }
  
  f(d1);
  f(d2);
  f(d3);
  f(3);
  f('0');
  f(c1);
  return 0;
}

Последний раз редактировалось Stilet; 04.06.2013 в 20:06.
Aspirisha вне форума Ответить с цитированием
Старый 04.06.2013, 19:14   #2
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Потому что размер адреса в Вашей архитектуре - 4 байта. Странный вопрос.
Молчу о том, что компилятор имеет полное право передавать аргументы через регистры или оптимизировать вызов иным образом, до тех пор пока это не нарушает наблюдаемого поведения программы.

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

Временные переменные создаются в вызывающем коде, в том случае, если построение ссылки на формально переданный аргумент невозможно. Если я не ошибаюсь, это верно для символьных (но не строковых) литералов, нумералов (числовых констант), в случае если переданный аргумент не есть lvalue (f(2+5)), а также, возможно, в том случае, если требуется нетривиальное преобразование типа.
Abstraction вне форума Ответить с цитированием
Старый 04.06.2013, 19:38   #3
Aspirisha
Пользователь
 
Регистрация: 12.11.2012
Сообщений: 20
По умолчанию

Спасибо за ответ!
Дело в том, что касательно адреса: если сделать f(void), смещение оказывается 0 байт. Но адрес по вашей логике должен писаться.
Про передачу через регистры: если сделать f(long long c), будет смещение 8 байтов.
И да, кончено оптимизация полностью отключена.
Aspirisha вне форума Ответить с цитированием
Старый 04.06.2013, 21:22   #4
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Дело в том, что касательно адреса: если сделать f(void), смещение оказывается 0 байт. Но адрес по вашей логике должен писаться.
Про передачу через регистры: если сделать f(long long c), будет смещение 8 байтов.
И? А если сделать
Код:
f(const что-угодно& c)
, будет 4 байта. Потому что адрес - 4 байта.
Только я не вижу, какое отношение это имеет к Вашему заданию.
Abstraction вне форума Ответить с цитированием
Старый 04.06.2013, 23:53   #5
Aspirisha
Пользователь
 
Регистрация: 12.11.2012
Сообщений: 20
По умолчанию

Да, вы правы насчет адреса. Я почему-то сначала подумал, что имеется в виду адрес возврата.
Да, мне хочется понять когда создается временная переменная. Я рассуждал так: размер long long у меня 8, значит я точно смогу отличить адрес переменной от новой переменной. Но при всех входных данных смещение 4 байта! Хотя при передаче rvalue уж точно должна создаваться переменная! Где подвох?
Aspirisha вне форума Ответить с цитированием
Старый 05.06.2013, 00:03   #6
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Хотя при передаче rvalue уж точно должна создаваться переменная! Где подвох?
Цитата:
Временные переменные создаются в вызывающем коде, в том случае, если построение ссылки на формально переданный аргумент невозможно.
Что вполне логично: нам нужно передать адрес - значит, объект по этому адресу должен существовать до начала вызова функции, значит это не может быть локальная переменная функции.
Abstraction вне форума Ответить с цитированием
Старый 05.06.2013, 00:29   #7
Aspirisha
Пользователь
 
Регистрация: 12.11.2012
Сообщений: 20
По умолчанию

То есть, метод не прокатывает. Но тогда вопрос, как понять, была ли создана временная переменная? Например, в случае передачи unsigned long / char? Ведь обычная неконстантная ссылка считает разными типами даже char & и signed char &?
Aspirisha вне форума Ответить с цитированием
Старый 05.06.2013, 10:54   #8
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Но тогда вопрос, как понять, была ли создана временная переменная? Например, в случае передачи unsigned long / char? Ведь обычная неконстантная ссылка считает разными типами даже char & и signed char &?
Подумайте вот о чём: в Вашем задании сказано не "когда создаются временные переменные при компиляции кода данным компилятором с заданными опциями компиляции", не так ли? Значит, любое практическое исследование в лучшем случае может подсказать ответ, но никак не обосновать его.

"Обычный" char - это либо signed char, либо unsigned char. Стандарт (по крайней мере 2003) не оговаривает, какой именно, это решение оставлено на усмотрение разработчика компилятора.
Abstraction вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
C++ локальные переменные Вечный_студент Общие вопросы C/C++ 6 15.03.2012 20:48
Локальные переменные и запрос NewLine C/C++ Базы данных 1 21.02.2011 00:06
Локальные переменные vs Глобальные Sibedir Общие вопросы Delphi 27 01.01.2011 13:02
Локальные переменные Sibedir Общие вопросы Delphi 30 24.12.2010 04:42
Локальные и глобальные переменные. Proger10 Общие вопросы Delphi 1 04.05.2009 05:55