Функциональность ссылки «self» или «this» в PLAIN C

Я использую парадигму псевдо-операции с простым c и хотел бы, чтобы указатель функции структуры имел доступ к остальным данным структуры.

Единственный способ сделать это - передать ссылку «текущий объект» в каждую функцию, например

struct MyStructure{
    //NOTE I want to access this member:
    struct MyStructure *self;
    
    int var1;
    int var2;
    
    void ( *initMemberFn    )(MyStructure *self, int arg1, int arg2);
    void ( *memberFn1       )(MyStructure *self);
    
};

void initMemberFn(MyStructure *self, int arg1, int arg2){   
    (*self).var1 = arg1;
    (*self).var2 = arg2;
    
}

void memberFn1(MyStructure *self){
    //NOTE Access the above member HERE without passing the self argument
    printf("var1:%d, var2:%d", (*self).var1, (*self).var2 );
    
}


int main(){
    
    MyStructure mystruct;
    mystruct.self = &mystruct;

    mystruct.initMemberFn = &initMemberFn;
    mystruct.memberFn1 = &memberFn1;

    mystruct.initMemberFn(mystruct.self, 1, 2);
    mystruct.memberFn1(mystruct.self);
    
}

Отмечу, что это работает не на всех компиляторах, но я использую cl.exe Visual Studio.

Есть ли какой-либо (другой) способ получить доступ к самому члену структуры изнутри одной из функций?

(Я отметил соответствующие строки с комментариями.)

Для этого вы можете использовать макрос, например CALL_MEMBER(struct_name, method_name). В противном случае нет никакого способа, потому что ваши функции могут вызываться для разных «экземпляров» MyStructure, и они не смогут узнать, какой из них.

Eugene Sh. 13.08.2024 17:06

Добавить (*self).self = self; к initMemberFn()?

chux - Reinstate Monica 13.08.2024 17:06

Обычный способ — передать &mystruct напрямую. Я думаю, вы получите отрицательное значение, если в вашей структуре есть поле self, которое должно совпадать с адресом структуры. Вы можете определить макрос, чтобы избежать двойного указания объекта.

Paul Hankin 13.08.2024 17:06

@chux-ReinstateMonica Я попробовал это, это работает для его назначения, но не дает доступа изнутри.

stackoverflow909 13.08.2024 17:08

Примечание: в C есть специальный оператор, поэтому вам не нужно писать (*self).var. Вместо этого используйте self->var

Verpous 13.08.2024 17:09

@Verpous Мне придется начать использовать это - я всегда путаю операторы указателей в c

stackoverflow909 13.08.2024 17:13

Адрес, хранящийся в mystruct.self = &mystruct;, будет неверным, если вы присвоите всю структуру, например mystruct1 = mystruct2;, или передадите структуру по значению функции.

Bodo 13.08.2024 17:33

В коде отсутствует определение типа для типа MyStructure.

Ian Abbott 13.08.2024 17:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
72
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Есть ли какой-либо (другой) способ получить доступ к самому члену структуры изнутри одной из функций?

Нет.

В C нет понятия объектных методов, таких как C++ (или другие ООП-языки), есть только глобальные функции.
С точки зрения функции нет self/this и т. д., если вы явно не передадите его как параметр.
Тот факт, что функция вызывается через указатель функции, хранящийся в структуре, не имеет существенного значения.

Как предложено в комментарии, вы можете использовать метку, чтобы сделать звонок немного короче, но это не изменит этот основной факт, а лишь до некоторой степени скроет его (что лично мне кажется менее ясным).

Примечание:
В языках ООП, таких как C++, C# и т. д., на самом деле внутри все будет так же, как и в C, т. е. указатель или ссылка на текущий объект будет передан функции в коде, сгенерированном компилятором.

В известных мне объектно-ориентированных языках это делается путем неявной передачи ссылки на методы экземпляра экземпляра. Например, C++ и Swift передают ссылку на экземпляр в качестве первого параметра в методах экземпляра. Если вы когда-нибудь посмотрите на ассемблерный код, сгенерированный для метода экземпляра, вы это увидите.

Вы не можете сделать это в C, поэтому вам придется передать ссылку явно, как вы это сделали для void memberFn1(MyStructure *self).

Что вы подразумеваете под словом неявно? Например, в языке oo есть встроенный макрос?

stackoverflow909 13.08.2024 17:15

@ stackoverflow909 Это означает, что обозначение object.method(a,b,c) является синтаксическим сахаром для вызова method(&object, a,b,c) (ну, типа того).

Eugene Sh. 13.08.2024 17:17

@ЕвгенийШ. Да, у меня было ощущение, что это именно так, потому что я думаю, что это... питон? это требует, чтобы вы передали (или определили?) self в качестве параметра для функций-членов.

stackoverflow909 13.08.2024 17:19

да, вы можете увидеть подсказки в Python, Rust и тому подобном.

Eugene Sh. 13.08.2024 17:20

Да, что @EugeneSh. сказал. Большая разница между функциями-членами и другими функциями заключается в том, что первые получают указатель this в качестве первого параметра, даже если вы не видите его в коде (именно это делает его «неявным»). Компилятор обрабатывает это; вы не видите его как пользователь, но знаете, что можете ссылаться на this в любой функции-члене.

Caleb 13.08.2024 17:28

ООП-компиляторы автоматически делают (почти) именно то, что вы написали, то есть неявно передают указатель this в качестве первого аргумента. Некоторые компиляторы (в частности, MSVC) передают this через регистр, даже если все остальные аргументы передаются через стек. Однако точная реализация зависит от компилятора и не предусмотрена спецификацией C++.

Не-ООП-компиляторы, конечно, этого не делают, и вам нужно явно передать все аргументы, включая this (или self в вашем примере).

«Почти точно» — потому что нет смысла добавлять член self в MyStructure, поскольку он не приносит никакой пользы, а только занимает место в памяти.

«Почти точно» также связано с тем, что языкам ООП не требуется хранить указатели функций методов в объектах.

Ian Abbott 13.08.2024 18:05

Другие вопросы по теме