Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.86/14: Рейтинг темы: голосов - 14, средняя оценка - 4.86
0 / 0 / 0
Регистрация: 28.10.2018
Сообщений: 4
1

Функции с переменным количеством параметров

30.06.2021, 14:00. Показов 2689. Ответов 19
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Почему не работает следующий код (gcc 9.3.0; Ubuntu 20.04):
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
int sum(int paramN, ...)
{
    int *p = &paramN;
    int s = 0;
    while (paramN) {
        s += *(++p);
        paramN--;
    }
    return s;
}
 
int main(void)
{
    printf("%d\n", sum(3, 5, 3, 2));
    return 0;
}
Ожидаю, что функция sum() вернет 10, но она возвращает 1180573096. Где ошибка? Или это особенности компилятора?
А так работает:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdarg.h>
 
int sum(int paramN, ...)
{
    va_list p;
    int s = 0;
    va_start(p, paramN);
    while (paramN) {
        s += va_arg(p, int);
        paramN--;
    }
    va_end(p);
    return s;
}
 
int main(void)
{
    printf("%d\n", sum(3, 5, 3, 2));
    return 0;
}
Помогите разобраться.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.06.2021, 14:00
Ответы с готовыми решениями:

Написание функции с переменным количеством параметров
Написать функцию с переменным количеством параметров. Первым параметром передавать количество...

Возвращение массива в функции с переменным количеством параметров
задание Пoследoвaтeльнocть вещeствeнныx пoлoжитeльныx пеpeмeнных, ограничeннaя пeремeннoй co...

Функция с переменным количеством параметров
Почему выводит всякую ерунду #include &lt;stdio.h&gt; #include &quot;stdio.h&quot; #include &quot;stdlib.h&quot; int...

Функция с переменным количеством параметров
Разработать функцию с переменным количеством параметров (x1, x2, ..., xn), которая вычисляет...

19
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 14:26 2
Цитата Сообщение от _dalex Посмотреть сообщение
Помогите разобраться.
Компилятор 64-й, да?
Глянь:
Функции с переменным количеством параметров
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
30.06.2021, 14:29 3
Цитата Сообщение от _dalex Посмотреть сообщение
Почему не работает следующий код
Потому что он неверный.
Так делать нельзя.
Язык не дает никаких гарантий, что такой хак будет работать.

Цитата Сообщение от _dalex Посмотреть сообщение
А так работает:
А этот код верный. Так делать правильно.
0
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 14:34 4
Цитата Сообщение от DrOffset Посмотреть сообщение
Так делать нельзя.
Ну зря ты так, чувак просто хочет знать, как этот механизм работает.
Мне, кстати, тоже интересно.

Короче, переменные параметры компайлер пихает в размер указателя (для 64 битного компайлера это 8 байт).
Я этого не знал.

Прибил гвоздями везде 8-байтные типы данных и заработало.

Функции с переменным количеством параметров


Канешна, лучше так не делать. Особенно когда пишешь чонить кроссплатформенное. Эти макросы (va_xxx()) не просто так придумали.
1
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
30.06.2021, 14:59 5
Лучший ответ Сообщение было отмечено _dalex как решение

Решение

Цитата Сообщение от Verevkin Посмотреть сообщение
Короче, переменные параметры компайлер пихает в размер указателя (для 64 битного компайлера это 8 байт).
Я этого не знал.
Так это и не так нифига.
Вообще не так.

Цитата Сообщение от Verevkin Посмотреть сообщение
Ну зря ты так,
Если у человека вопрос по конкретной реализации, то начинать надо с того, что озвучить платформу и версию компилятора.
Тебе бы это тоже не помешало сделать, т.к. сейчас ты просто наделал ложных выводов из частной ситуации.

На 64-битной платформе первые аргументы вообще могут передаваться НЕ через стек, как например происходит здесь:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <stdint.h>
 
int64_t sum(int64_t paramN, ...)
{
    int64_t *p = &paramN;
    int64_t s = 0;
    while (paramN) {
        s += *(++p);
        paramN--;
    }
    return s;
}
 
int main(void)
{
    printf("%lld\n", sum(3, 5, 3, 2));
    return 0;
}
Assembler
1
2
3
4
5
6
        mov     ecx, 2
        mov     edx, 3
        xor     eax, eax
        mov     esi, 5
        mov     edi, 3
        call    sum
Пример для GCC. По понятным причинам это никак не может привести к результату 10. И не приводит.
Полный пример здесь: https://godbolt.org/z/faa1jexMb
1
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 15:03 6
Цитата Сообщение от DrOffset Посмотреть сообщение
На 64-битной платформе первые аргументы вообще могут передаваться НЕ через стек
допиши какойнить cdecl (ну типа принудительно передавай через стек), интересно жэж. А то я уже всё позакрывал, да и MSVC у меня нету.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
30.06.2021, 15:05 7
Цитата Сообщение от Verevkin Посмотреть сообщение
допиши какойнить cdecl, интересно жэж.
На 64-битной платформе вообще нет никаких calling convention (кроме основной, которая работает по умолчанию), если ты думаешь, что это как-то повлияет

Добавлено через 48 секунд
Verevkin, так ты напишешь название платформы и версию своего инструментария, или нет?
0
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 15:07 8
Цитата Сообщение от DrOffset Посмотреть сообщение
На 64-битной платформе вообще нет никаких calling convention (кроме основной, которая работает по умолчанию), если ты думаешь, что это как-то повлияет

Цитата Сообщение от DrOffset Посмотреть сообщение
так ты напишешь название платформы и версию своего инструментария, или нет?
У меня венда 10, codeblocks 20.03, компайлер gcc (mingw) x64.
0
DrOffset
30.06.2021, 15:21
  #9

Не по теме:

Verevkin, автор отметил ответ, поздравляю, уши еще одного новичка успешно завешаны лапшой :)
Естественно, очень многие люди охотнее соглашаются с тем, что им самим ближе, даже если это и не правильно.
Ну ничего, если работать потом пойдет, через боль таки научат. Или нет :)

0
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 15:28 10
Цитата Сообщение от DrOffset Посмотреть сообщение
втор отметил ответ, поздравляю, уши еще одного новичка успешно завешаны лапшой
Я просто высказал свою точку зрения. Она, чо, не имеет права быть неправильной? На чём я, кстати, и не настаиваю.
Если тебе это не нравится, напиши свою. У нас тут цензура есть, но плюрализм мнений никто не запретил (пока).

Для частного случая так себе обсуждение...
0
DrOffset
30.06.2021, 15:35
  #11

Не по теме:

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

0
0 / 0 / 0
Регистрация: 28.10.2018
Сообщений: 4
30.06.2021, 15:35  [ТС] 12
Ubuntu 20.04 (64bit) gcc 9.3.0
и так не работает:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <inttypes.h>
 
int64_t sum(int64_t paramN, ...)
{
    int64_t *p = &paramN;
    int64_t s = 0;
    while (paramN) {
        s += *(++p);
        paramN--;
    }
    return s;
}
 
int main(void)
{
    printf("%"PRId64"\n", sum(3, 5, 3, 2));
    return 0;
}
0
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 15:44 13
Цитата Сообщение от DrOffset Посмотреть сообщение
Если же он хотел просто удостовериться, что "код-то норм, просто компилятор глючит", то ты ему в этом помог, с чем я и поздравил.
Ну это ж неправда, я такого не говорил. И рассматривал только конкретный частный случай с тем компилятором, который у меня есть.
Цитата Сообщение от _dalex Посмотреть сообщение
и так не работает:
Ты не смотри, чо тебе на консоль вываливается. Смотри в дебаггере значения и память по указателю. Иначе так можно в угадайку играть, пока солнце не погаснет.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
30.06.2021, 15:56 14
Цитата Сообщение от Verevkin Посмотреть сообщение
Ну это ж неправда, я такого не говорил.
Так я и не говорю, что это ты говорил.
Это псевдоцитата на то, как поставлен вопрос в теме.
Он поставлен именно с таким акцентом.
0
Злостный нарушитель
9547 / 5176 / 1182
Регистрация: 12.03.2015
Сообщений: 24,445
30.06.2021, 16:01 15
Цитата Сообщение от DrOffset Посмотреть сообщение
Так я и не говорю, что это ты говорил.
Это псевдоцитата на то, как поставлен вопрос в теме.
Он поставлен именно с таким акцентом.
короче...
Кликните здесь для просмотра всего текста
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
30.06.2021, 16:13 16
Лучший ответ Сообщение было отмечено _dalex как решение

Решение

Цитата Сообщение от _dalex Посмотреть сообщение
и так не работает:
Не работает.
Потому что (вот дали вы платформу и можно уже конкретно разговаривать), на Ubuntu действует System V ABI, который предполагает передачу первых аргументов функции в регистрах. Т.е. прогуляться по регистрам, как по стеку через указатели не получится никак.

Еще более конкретно, идете вот в этот документ https://uclibc.org/docs/psABI-x86_64.pdf
И читаете параграфы 3.5.7 Variable Argument Lists и A.2.1 Calling Convention, там есть абсолютно все про вашу конкретную ситуацию.

Добавлено через 7 минут

Не по теме:

Цитата Сообщение от Verevkin Посмотреть сообщение
короче...
Ну и зря.
:)

2
0 / 0 / 0
Регистрация: 28.10.2018
Сообщений: 4
30.06.2021, 16:37  [ТС] 17
Ok. Спасибо. Теперь понятно! Когда у меня не получилось, пройтись по стеку, я подумал, что здесь параметры передаются не через стек, а в книге по которой я учу Си, про передачу параметров функции через регистры процессора ни чего не сказано. Еще раз большое спасибо за разъяснение.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
30.06.2021, 17:10 18
Цитата Сообщение от _dalex Посмотреть сообщение
а в книге по которой я учу Си, про передачу параметров функции через регистры процессора ни чего не сказано.
Если в книге есть такой код:
Цитата Сообщение от _dalex Посмотреть сообщение
int sum(int paramN, ...)
{
int *p = &paramN;
int s = 0;
while (paramN) {
s += *(++p);
paramN--;
}
return s;
}
то это вредная книга.
0
0 / 0 / 0
Регистрация: 28.10.2018
Сообщений: 4
30.06.2021, 17:18  [ТС] 19
Нет, там как раз второй вариант описывается с использованием stdarg.h, а первый это мое поделие думал можно просто брать параметры из стека зная из количество и типы.
0
Вездепух
Эксперт CЭксперт С++
12785 / 6663 / 1794
Регистрация: 18.10.2014
Сообщений: 16,854
30.06.2021, 22:23 20
Цитата Сообщение от _dalex Посмотреть сообщение
Почему не работает следующий код
А почему он вдруг должен работать? Очередная чушь с попыткой доступа к переменным параметрам без использования <stdarg.h>.
0
30.06.2021, 22:23
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.06.2021, 22:23
Помогаю со студенческими работами здесь

Функция с переменным количеством параметров
Привет всем. Возникла проблема с указателем в функции. Стоит задача: создать функцию, которая...

Написать функцию с переменным количеством параметров
Написать функцию NOK с переменным количеством параметров которая находит наименьшее общее кратное...

Разработать функцию с переменным количеством параметров
Добрый день, уважаемые программисты! Прошу помочь в поиске ошибки задание: Разработать функцию с...

Разработать функцию с переменным количеством параметров
Разработать функцию с переменным количеством параметров. Для извлечения параметров из списка...

Разработать функцию с переменным количеством параметров
Помогите пожалуйста: Разработать функцию с переменным числом параметров ({x}_{1}, {x}_{2}, ... ,...

Не получается создать функцию с переменным количеством параметров
void read_file(char fn,char tp,int count, int* tpi, ...){ FILE *cfile; int* j = &amp;tpi;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru