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

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

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 24.07.2012, 09:05   #21
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от netrino Посмотреть сообщение
В данном конкретном случае проблемы будут на 64-битных машинах и в принципе на любых компиляторах, где размер int отличается от размера машинного слова (по нему выравниваются значения в стеке). Единственный портабельный способ гулять по чужому стеку - va_list/va_start/va_arg/va_end, так работают vprintf и друзья.

Переменное кол-во значений обязательно? Было бы лучше поискать альтернативные решения (например просто определить Bar как ф-цию, которая принимает указатели или ссылки), потому как любой из способов для плюсов будет не типо-безопасным (разве только шаблоны переменной длины из C++11).
ААа... выравнивание.. значит.

А типобезопасность присутствует. При помощи тех же шаблонов, правда не variardic.


Вот такой подход учитывает выравнивание?

Код:
struct STest{ int a1; char a2; };

void Bar(void* ptr)
{
    STest* test = (STest*)ptr;
    cout<<"a1 = " <<(*test).a1<<endl;
    cout<<"a2 = " <<(*test).a2<<endl;
}

void Foo(int a1, int a2)
{
    Bar(&a1);
}

int main()
{
    Foo(10,'a');
      return 0;
}

Последний раз редактировалось _Bers; 24.07.2012 в 09:08.
_Bers вне форума Ответить с цитированием
Старый 24.07.2012, 20:23   #22
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
ААа... выравнивание.. значит.

А типобезопасность присутствует. При помощи тех же шаблонов, правда не variardic.


Вот такой подход учитывает выравнивание?

Код:
struct STest{ int a1; char a2; };

void Bar(void* ptr)
{
    STest* test = (STest*)ptr;
    cout<<"a1 = " <<(*test).a1<<endl;
    cout<<"a2 = " <<(*test).a2<<endl;
}

void Foo(int a1, int a2)
{
    Bar(&a1);
}

int main()
{
    Foo(10,'a');
      return 0;
}
Нет, такой тоже не подходит. Каждое значение в стеке выравнивается по размеру машинного слова (4 байта для 32х-битных архитектур, 8 для 64х-битных). В Вашем же случае, выравнивание будет по int (которое 4 байта на обоих архитектурах в основных реализациях). То есть при попытке доступа подобным образом к полям структуры, поле a2 не будет доступно на 64х-битных архитектурах.
Код:
          a1                   a2
stack: [_|_|_|_| _|_|_|_] [_|_|_|_|_|_|_|_]
          a1      a2
STest: [_|_|_|_][_|_|_|_]
Для верного итерирования по стеку нужно использовать типы, равные машинному слову, например size_t или ptridiff_t. Но и здесь всё равно нет гарантии корректности, всё же, если хочется работать с указателем на стэк, то используйте средства cstdarg.
netrino вне форума Ответить с цитированием
Старый 24.07.2012, 20:38   #23
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

а вы учли передачу не через стек?
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 24.07.2012, 20:46   #24
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от netrino Посмотреть сообщение
Нет, такой тоже не подходит. Каждое значение в стеке выравнивается по размеру машинного слова (4 байта для 32х-битных архитектур, 8 для 64х-битных). В Вашем же случае, выравнивание будет по int (которое 4 байта на обоих архитектурах в основных реализациях).
Получается, что выравнивание данных на стеке, и выравнивание данных в полях структур выполняется разными способами?
_Bers вне форума Ответить с цитированием
Старый 25.07.2012, 20:39   #25
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
Получается, что выравнивание данных на стеке, и выравнивание данных в полях структур выполняется разными способами?
Выравниванием данных в структуре занимается компилятор и это относится к "поведению определяемому реализацией", то есть может быть любым и даже меняться в зависимости от ключей компиляции. С другой стороны, выравнивание данных в стеке завязано на конкретную архитектуру и никак не зависит от языка программирования.

Как правило структуры выравниваются по наибольшему значению, что в них присутствует, а не по машинному слову. В Вашем примере структура будет занимать 8 байт (каждое поле по 4 байта), что опять таки не годится, ведь на 64-битных машинах два переданных значения будут занимать в сумме 16 байт в стеке (что видно на схеме, которую я привёл в предыдущем посте).
netrino вне форума Ответить с цитированием
Старый 25.07.2012, 20:56   #26
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от netrino Посмотреть сообщение
Выравниванием данных в структуре занимается компилятор и это относится к "поведению определяемому реализацией", то есть может быть любым и даже меняться в зависимости от ключей компиляции. С другой стороны, выравнивание данных в стеке завязано на конкретную архитектуру и никак не зависит от языка программирования.

Как правило структуры выравниваются по наибольшему значению, что в них присутствует, а не по машинному слову. В Вашем примере структура будет занимать 8 байт (каждое поле по 4 байта), что опять таки не годится, ведь на 64-битных машинах два переданных значения будут занимать в сумме 16 байт в стеке (что видно на схеме, которую я привёл в предыдущем посте).
Вах вах! А я почему то думал, что структуры выравниваются так, что б были кратны машинному слову...

Ну вот взять например:

Код:
struct ddd
{
    LONG64 test; //8 байт
    char d;
};

cout<<sizeof(ddd)<<endl; //16 байт
7мь байт просто в никуда!

Я думал, что компиль выравнивает структуры так же, как и аргументы на стеке.

Но дело даже не в этом.

Дело вот в чем:

Код:
//взял адрес первого аргумента, и без проблем вытащил все аргументы, без необходимости копировать все аргументы
void Foo(int a1, int a2);
Код:
//Первый аргумент взялся без проблем. А вот второй уже не вывелся. Вместо корректного значения, в памяти оказался какой то мусор
void Foo(const int& a1, const int& a2);
Проблема в том, что я понятия не имею о том, на что можно рассчитывать вообще, и как компиляторы хранят аргументы на стеке.

Судя по поведению, во втором случае, компилятор разместил аргументы не один за другим на стеке, а черти как. Та область, которая якобы была предназначена для второго аргумента - там оказалось непонятное нечто.

В общем, я решил вообще отказаться от идеи транспортировки данных по адресу первого аргумента.

Лучше пусть будет лишнее копирование всех аргументов, но это будет безопасно, контролируемо, и портируемо.

/зы Всякие макросы с которыми работают printf и компания - не помогли. Я так и не понял причину мусора на месте второго аргумента.

Последний раз редактировалось _Bers; 25.07.2012 в 20:59.
_Bers вне форума Ответить с цитированием
Старый 26.07.2012, 01:48   #27
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
Проблема в том, что я понятия не имею о том, на что можно рассчитывать вообще, и как компиляторы хранят аргументы на стеке.
Так в том и проблема, что рассчитывать нельзя ни на что (за исключением параметров переменной длины из cstdarg, оно гарантированно корректно извлекает данные на любой платформе, но требует именно ф-ции переменной длины, то есть мы жертвуем безопасностью и корректностью типов).

Цитата:
Сообщение от _Bers Посмотреть сообщение
В общем, я решил вообще отказаться от идеи транспортировки данных по адресу первого аргумента.

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


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
malloc в С++ _Kitten_ Помощь студентам 2 12.12.2011 19:20
Malloc Sabin4ik Общие вопросы C/C++ 12 18.02.2011 01:13
функция malloc() для разного типа переменной. Serjuk Помощь студентам 46 05.01.2010 21:52
SIEGSEGV в malloc() TheVampire Общие вопросы C/C++ 0 25.09.2009 14:32
Проблема с malloc Обледеневший Общие вопросы C/C++ 7 14.09.2009 18:06