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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 19.09.2016, 15:41   #11
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

Цитата:
Сообщение от RaisaR Посмотреть сообщение
чем заменить функцию gets
fgets
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 20.12.2016, 11:36   #12
Sabre
Пользователь
 
Регистрация: 13.09.2016
Сообщений: 16
По умолчанию

Есть функция, которая принимает массив строк (указателей на строки) переменной длины. Признак конца - нулевой указатель. Макросы va_arg не использую в академических целях - хочу глубже понять механизм передачи параметров и работать с параметрами непосредственно.
Код:
void strfunc(WCHAR* str, ...) {
	uintptr_t* arg = (uintptr_t*)&str;

	MessageBox(0, (WCHAR*)*arg, APPNAME, MB_OK);
	MessageBox(0, (WCHAR*)*++arg, APPNAME, MB_OK);
Функция рабочая, корректно выводит MessageBox-ы. Но чтобы код скомпилировался без ворнингов, приходится применять приведение типов. Сначала мы приводим указатель на строку, к указателю на адрес, с тем, чтобы передвигаться по переданным в функцию параметрам (...). Затем разыменовываем указатель на адрес, и приводим его к типу указателя на строку обратно. Подскажите, можно ли написать код проще/лучше, возможно без приведений? value=*arg само собой.
Sabre вне форума Ответить с цитированием
Старый 20.12.2016, 11:41   #13
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
Макросы va_arg не использую
Посему результат может быть совершенно непредсказуем.
Croessmah вне форума Ответить с цитированием
Старый 20.12.2016, 12:07   #14
Sabre
Пользователь
 
Регистрация: 13.09.2016
Сообщений: 16
По умолчанию

Цитата:
Сообщение от Croessmah Посмотреть сообщение
Посему результат может быть совершенно непредсказуем.
Вполне даже предсказуем. Благодаря тому, что решил копнуть поглубже как оно происходит, а не слепо скопировать конструкции va_list и т. д. я понял как формируется кадр стека, какие параметры и как фактически передаются при вызове функции. В каком случае мы получаем segfault при работе с такими функциями, а в каких случаях можно безопасно работать с параметрами. Само собой, для вызова такой функции лучше использовать макрос, который добавляет 0 последним параметром, чтобы избежать потенциальных ошибок при вызове подобной функции (макросы va_arg от таких ошибок тоже не страхуют).
Sabre вне форума Ответить с цитированием
Старый 20.12.2016, 12:18   #15
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от Sabre Посмотреть сообщение
я понял как формируется кадр стека
Да, на вашем конкретном процессоре. На других все может быть по другому. Именно для этого и созданы эти макросы.
Ну а будем следовать стандарту или нет, это конечно дело каждого...
waleri вне форума Ответить с цитированием
Старый 20.12.2016, 12:43   #16
Sabre
Пользователь
 
Регистрация: 13.09.2016
Сообщений: 16
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Да, на вашем конкретном процессоре. На других все может быть по другому. Именно для этого и созданы эти макросы.
Ну а будем следовать стандарту или нет, это конечно дело каждого...
Я всё прекрасно понимаю. Как можно заметить, код использует WinAPI, а значит не предполагается, что он должен работать на других системах кроме винды. А раз программа под винду, то на любом процессоре, на котором запускается винда, она будет работать (кроме, возможно, Итаниума). Именно поэтому использован переносимый тип uintptr_t, а не int/long, который работает под вин32, но не работает под вин64 или long long, с которым всё наоборот. Понимание что такое соглашение о вызовах, какие они бывают под вин32/64, кмк, не повредят ни одному программисту.

Еще раз подчеркну - пример академический. Я полностью отдаю себе отчёт в том, что в коммерческом коде такие велосипеды недопустимы.
Sabre вне форума Ответить с цитированием
Старый 20.12.2016, 14:22   #17
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

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

Что касается кастов, то что-то у Вас не так с ними.
Зачем Вы кастите к uintptr_t*, а затем обратно к WCHAR*?

Последний раз редактировалось Croessmah; 20.12.2016 в 14:32.
Croessmah вне форума Ответить с цитированием
Старый 20.12.2016, 14:32   #18
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Код:
#include <stdio.h>


void func(wchar_t *arg, ...)
{
    
    wprintf(L"%s\n", *&arg);
    wprintf(L"%s", *(&arg + 1));
}


int main()
{
    func(L"first", L"second");
}
http://rextester.com/UITAB47313

Но если собрать другим компилятором, то оно может и не заработать.
Например, сейчас попробовал с MinGW.
С опцией -O1 работает, с опцией -O2 - нет.
VC не имею, но может и там будет зависеть от опций.

Последний раз редактировалось Croessmah; 20.12.2016 в 14:47.
Croessmah вне форума Ответить с цитированием
Старый 20.12.2016, 14:45   #19
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Проверил приведенный Вами код.
Работает и на MinGW, но
если MessageBox поменять на wprintf,
то оно перестает работать в MinGW уже с опцией -O2.

Так что Вы там говорили о предсказуемости?

Последний раз редактировалось Croessmah; 20.12.2016 в 14:48.
Croessmah вне форума Ответить с цитированием
Старый 20.12.2016, 15:35   #20
Sabre
Пользователь
 
Регистрация: 13.09.2016
Сообщений: 16
По умолчанию

Цитата:
Сообщение от Croessmah Посмотреть сообщение
Зачем Вы кастите к uintptr_t*, а затем обратно к WCHAR*?
Потому что, хоть и первоначальный код:
Код:
uintptr_t* arg = &str;
MessageBox(0, *arg, APPNAME, MB_OK);
MessageBox(0, *++arg, APPNAME, MB_OK);
работает как надо, но при компиляции VS ругается на несоответствие типов в каждой строчке. При помощи кастов, я просто даю компилятору понять, что так задумано, убирая предупреждения. Но мне самому кажется такое решение... непрозрачным что-ли... и можно это выразить проще.

Цитата:
Сообщение от Croessmah Посмотреть сообщение
С опцией -O1 работает, с опцией -O2 - нет.
VC не имею, но может и там будет зависеть от опций.
Интересно было бы глянуть ассемблерный листинг что он там наоптимизировал под x64 Я собираю в версии дебага с /Od - без оптимизации, а в релизной с /Ox /Oi - максимальная оптимизация с разворачиванием подставляемых функций. Результат одинаков, как и должно быть.

Цитата:
Сообщение от Croessmah Посмотреть сообщение
Код:
*(&arg + 1)
Гениально! Вот та конструкция, до которой я самостоятельно не додумался, и начал придумывать вариант с указателем на массив параметров и кастами, а затем создал эту тему. Это то, что я хотел. Большое спасибо! Признаюсь, видел эту конструкцию уже в какой-то книге, но одно дело когда читаешь, всё кажется очевидным и понятным, другое - когда садишься кодить.
Sabre вне форума Ответить с цитированием
Ответ


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

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
первые шаги в андройде Виталий.Ч . Помощь студентам 2 11.03.2016 16:19
Первые шаги к свободе 13th Свободное общение 15 19.01.2012 00:58
Первые шаги в QBasic teeshka2 Помощь студентам 2 23.08.2010 14:47
первые шаги в с++ ploik Общие вопросы C/C++ 2 16.07.2010 23:35
Первые шаги trave1er Общие вопросы C/C++ 2 10.09.2008 20:32