Почему функция внутри структуры работает на языке Си
Как показано в этом небольшом сценарии.
#include <stdio.h>
struct student{
short count;
void (*addCount)();
};
void student_addCount(struct student a){
a.count++;
}
int main(){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount();
student.addCount();
student.addCount();
student.addCount();
student.addCount();
printf("%d\n",student.count);
}
Я добавил указатель на функцию внутри структуры, но я не знаю, почему это работает, поскольку функция 'addCount' не получает никаких аргументов и фактически добавляет указанное количество раз.
Я компилирую этот код с помощью GCC 6.3.0 в различных средах, таких как ideone.com, wandbox.org и компилятор в WSL.
Вот доказательство того, что это работает с Ideone. https://ideone.com/Cam4xY
1 ответ
Это не функция внутри структуры, это указатель на функцию внутри структуры.
void (*addCount)();
определяет addCount
как указатель на функцию. Функция возвращает void
и принимает неопределенное количество аргументов.
Вот что означают пустые скобки. Это объявление функции, не являющейся прототипом, в старом стиле. Редко, если вообще когда-либо, есть веская причина использовать не прототипные объявления или определения функций. Если вы хотите указать, что функция не принимает аргументов, используйте (void)
скорее, чем ()
,
student.addCount = student_addCount;
Функция student_addCount
занимает struct student
аргумент, но его тип по-прежнему совместим с типом вашего члена указателя. Назначение этого по существу отключает проверку вызовов. Вот почему объявления функций в старом стиле - плохая идея.
student.addCount();
Это косвенный вызов через указатель функции. Поскольку тип указателя на функцию не указывает, сколько аргументов ожидается, вызов является допустимым. Поскольку вызываемая функция требует одного аргумента типа struct student
, поведение не определено. С объявлениями функций старого стиля, программист, полностью зависит от вас правильности аргументов; компилятор вам не поможет.
Поскольку вы получаете то, что кажется верным результатом, вполне вероятно, что аргумент, который вы ожидали передать, оказался в нужном месте в памяти, возможно, на вершине стека. Функция вызывается, и она вполне разумно предполагает, что вы передали правильное значение аргумента. Он ищет этот аргумент в памяти или в регистре и находит... что-то.
Вот версия вашей программы без неопределенного поведения:
#include <stdio.h>
struct student{
short count;
void (*addCount)(struct student a);
};
void student_addCount(struct student a){
a.count++;
}
int main(void){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount(student);
student.addCount(student);
student.addCount(student);
student.addCount(student);
student.addCount(student);
printf("%d\n",student.count);
}
Выход 0
-- поскольку count
приращение является членом параметра, который является локальным объектом.
Вот версия, которая делает то, что вы, вероятно, хотите. Он передает указатель на структуру, поэтому count
член вашего оригинала struct student
Объект увеличивается с помощью функции. Выход 5
,
#include <stdio.h>
struct student{
short count;
void (*addCount)(struct student *a);
};
void student_addCount(struct student *a){
a->count++;
}
int main(void){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
printf("%d\n",student.count);
}