Ошибка несовместимых типов указателей только на моем локальном компьютере, а не в онлайн-IDE

Я освежал свои шаблоны проектирования на C здесь, и пока пытался запустить этот пример дизайна метода объекта, который у них на сайте:

#include <stdio.h>

// Define a structure to represent an object
typedef struct {
    // Data members
    int value;

    // Function pointer for a method
    void (*print)(const struct MyObject *);
} MyObject;

// Method to print the value of the object
void printValue(const MyObject *obj) {
    printf("Object value: %d\n", obj->value);
}

// Function to initialize an object
void initializeObject(MyObject *obj, int initialValue) {
    obj->value = initialValue;
    obj->print = &printValue; // Assign the function pointer
}

int main() {
    // Create an instance of MyObject
    MyObject myObj;

    // Initialize the object
    initializeObject(&myObj, 42);

    // Use the object's method
    myObj.print(&myObj);

    return 0;
}

Я получаю эти ошибки:

main.c:9:30: warning: declaration of 'struct MyObject' will not be visible outside of this function [-Wvisibility]
  void (*print)(const struct MyObject *);
                             ^
main.c:20:14: error: incompatible function pointer types assigning to 'void (*)(const struct MyObject *)' from 'void (*)(const MyObject *)' [-Wincompatible-function-pointer-types]
  obj->print = &printValue; // Assign the function pointer
             ^ ~~~~~~~~~~~
main.c:31:15: warning: incompatible pointer types passing 'MyObject *' to parameter of type 'const struct MyObject *' [-Wincompatible-pointer-types]
  myObj.print(&myObj);
              ^~~~~~
2 warnings and 1 error generated.

Для меня это имеет смысл, поскольку структура MyObject не имеет необходимой видимости. Он отлично работает, когда я меняю его на:

typedef struct MyObject {
  // Data members
  int value;

  // Function pointer for a method
  void (*print)(const struct MyObject *);
} MyObject;

Мне просто интересно, почему он компилируется во всех онлайн-IDE

Редактировать:

Он компилируется в примере, приведенном в ссылке:

гикифоргики

А также эти: туториалпойнт

кодеф

Это были первые три, которые я попробовал, но я вижу, что некоторые сейчас выдают одни и те же ошибки.

почему он компилируется во всех онлайн-IDE. Это неправда: godbolt.org/z/nevzWbohW

3CxEZiVlQ 05.09.2024 05:59

В C вы ссылаетесь на две разные структуры: анонимную структуру с псевдонимом typedef MyObject и совершенно отдельный тип структуры с тегом MyObject, который вы никогда не определяли. Это не должно компилироваться. Вы уверены, что используете онлайн-компилятор C, а не C++? В C пространство имен тега структуры отличается от глобального пространства имен.

Avi Berger 05.09.2024 06:00

Пожалуйста, измените вопрос и предоставьте хотя бы один экземпляр онлайн-IDE, в которой он компилируется.

Allan Wind 05.09.2024 06:59

Он компилируется в примере, приведенном в ссылке: geeksforgeeks А также эти: tutorialspoint codechef Это были первые три, которые я пробовал, но я вижу, что некоторые сейчас выдают одни и те же ошибки.

jebuschrast 05.09.2024 22:05

Вы хотите отредактировать свой вопрос, добавив дополнительные данные, вместо того, чтобы отвечать комментарием.

Allan Wind 05.09.2024 22:10
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

«Почему он компилируется во всех онлайн-IDE» явно ложно. Вы не пробовали их все, и @3CxEZiVlQ предоставил вам противоположный пример. Выше вы показываете одну ошибку, присвоение несовместимых типов и два предупреждения. Сообщение об ошибке совершенно ясно показывает, что obj->print и &printValue — совершенно не связанные типы указателей. Это может работать и действительно работает в данном случае, но эти онлайн-IDE должны генерировать ошибку.

Вы можете заставить это скомпилироваться без каких-либо ошибок и предупреждений с помощью предварительного объявления и пары приведений. Это связано с тем, что разыменование происходит объявленного типа и struct MyObject * является сквозным.

#include <stdio.h>

struct MyObject;

typedef struct {
    int value;
    void (*print)(const struct MyObject *);
} MyObject;

void printValue(const MyObject *obj) {
    printf("Object value: %d\n", obj->value);
}

void initializeObject(MyObject *obj, int initialValue) {
    obj->value = initialValue;
    obj->print = (void (*)(const struct MyObject *)) &printValue;
}

int main() {
    MyObject myObj;
    initializeObject(&myObj, 42);
    myObj.print((struct MyObject *) &myObj);
}

Было бы более понятно использовать const void * вместо const MyObject void *, и теперь вам нужно только выполнить приведение перед разыменованием:

#include <stdio.h>

typedef struct {
    int value;
    void (*print)(const void *);
} MyObject;

void printValue(const void *obj) {
    printf("Object value: %d\n", ((MyObject *) obj)->value);
}

void initializeObject(MyObject *obj, int initialValue) {
    obj->value = initialValue;
    obj->print = &printValue;
}

int main() {
    MyObject myObj;
    initializeObject(&myObj, 42);
    myObj.print(&myObj);
}

Конечно, лучший вариант — объявить struct MyObject, как вы указали.

В этом объявлении typedef

typedef struct {
    // Data members
    int value;

    // Function pointer for a method
    void (*print)(const struct MyObject *);
} MyObject;

в этой строке в объявлении безымянной структуры введены два разных спецификатора типа: спецификатор типа безымянной структуры с псевдонимом MyObject и спецификатор неполного типа структуры struct MyObject.

    void (*print)(const struct MyObject *);
                        ^^^^^^^^^^^^^^^

Более того, областью действия этого спецификатора типа struct MyObject является область действия прототипа функции. То есть это объявление не видно за пределами списка параметров функции.

Эти типы несовместимы.

Чтобы избежать ошибок, просто измените объявление следующим образом:

typedef struct MyObject{
    // Data members
    int value;

    // Function pointer for a method
    void (*print)(const struct MyObject *);
} MyObject;

Обратите внимание, что этот оператор присваивания

obj->print = &printValue; // Assign the function pointer

также может быть переписано как

obj->print = printValue; // Assign the function pointer

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

Что касается компиляторов, то реализация определяет, будут ли компиляторы выводить предупреждения как ошибки, и это зависит от опций компилятора.

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