воскресенье, октября 14, 2007

Статья Reading C type declarations

Чтение сложных объявлений типов в C/C++ задача непростая. Нет, все когда-то слышали, что надо идти кажется направо, а потом вроде налево и тем еще что-то про скобки было, но вот такое объявление может поставить в тупик:
int (*(*)())()

В статье Reading C type declarations приведено подробное описание и наглядные примеры расшифровки таких объявлений. Встречаются они редко, но всегда в самое неподходящее время...

20 комментариев:

  1. ИМХО самое ужастное, что есть в C - это указатели на функции.

    ОтветитьУдалить
  2. Да ничего ужасного в них нет. Просто с ними редко приходится работать и синтаксис у программиста вылетает из головы. Если руку набить, то работать с ними становится легко и приятно.

    ОтветитьУдалить
  3. Тут определяется указатель на функцию, не принимающую аргументов и возвращающую указатель на функцию, которая возращает int и так же непринимает аргументов.

    ОтветитьУдалить
  4. то есть эквивалентно такому коду

    typedef int (*foo)();
    typedef foo (*bar)();

    ОтветитьУдалить
  5. Я не говорю, что это чрезмерно сложно. Просто это очень некрасиво. В во многих других языках это сделано гораздо красивее.

    ОтветитьУдалить
  6. Э-м-м... А это не указатель на функцию, типы аргументов которой не определены?

    ОтветитьУдалить
  7. Э-м-м... А это не указатель на функцию, типы аргументов которой не определены?

    Не очень поняла, что значит "типы аргументов не определены". Там две функции, обе без аргументов.
    Вообще Nunquam dormio написал правильный тип. По ссылке рассказывается как он получается.

    ОтветитьУдалить
  8. Nunquam dormio пишет...
    Да ничего ужасного в них нет. Просто с ними редко приходится работать и синтаксис у программиста вылетает из головы. Если руку набить, то работать с ними становится легко и приятно.

    Собсвенно мне приходилось писать под платформу, на которой был только C компилятор(причём результат компиляции выполнялся на виртуальной машине). А хотелось с минимальными усилиями перенести туда кучу кода на C++. И для этой платформы я разрабатывал фрэймворк, использующий что-то вроде классов с наследовнием и виртуальными функциями. Вся система была достаточно сильно завязана на указатели на функции. Работать с ними было действительно легко, но почему-то хотелось лучшего.

    ОтветитьУдалить
  9. Анонимный15/10/07 10:17

    void не вписан, для C это и будет, что аргументы и их кол-во не определено

    ОтветитьУдалить
  10. Анонимусу: сенькс, именно это я и собирался написать.

    ОтветитьУдалить
  11. Чтобы было понятнее:
    $ cat > test.c << EOF
    > void test(){}
    > int main(){
    > test(1);
    > return 0;
    > }
    > EOF
    $ gcc -o test.exe test.c
    $ cat > test1.c << EOF
    > void test(void){}
    > int main(){
    > test(1);
    > return 0;
    > }
    > EOF
    $ gcc -o test1.exe test1.c
    test1.c: In function `main':
    test1.c:3: error: too many arguments to function `test'

    ОтветитьУдалить
  12. Анонимный15/10/07 11:17

    Скобки без аргументов или скобки с void означают, что у функции нет аргументов вообще, а не "количество неопределено".

    Неопределенное количество аргументов это >= 0 (см. printf(const char*,...) у которого параметров может быть >=1).

    ОтветитьУдалить
  13. Анонимный15/10/07 11:23

    Все подобные определения можно сделать более удобочитабельными путём последовательного создания нескольких typedef'ов. Но некоторым кажется, что лучше сэкономить пару строк кода, ведь все равно в данной конструкции они для себя разобрались.

    ОтветитьУдалить
  14. Анонимный15/10/07 11:36

    Хм. сабж поста был Reading С (!)type declarations, т.е migmit и иже :) правы, а nixaroid... немножко невнимателен.

    ;) sse

    ОтветитьУдалить
  15. Анонимный15/10/07 11:37

    ...прям как я :-[ прошу прощения у niRaXoid'а

    ОтветитьУдалить
  16. Анонимный16/10/07 10:44

    Анонимный(15/10/07 11:36), то есть, как я понял, отсутствие аргументов в скобках не эквивалентно (void) для С???

    В статье кстати не затрагивали аргументы функции для того, чтобы не загромождать процесс разбора типа. Но абстрактное определение С
    int (*(*foo)())()
    будет отличатсья от
    int (*(*foo)(int))().

    А void f(void); эквивалентно void f();

    Или я не прав?

    ОтветитьУдалить
  17. Не прав. См. приведённый мною выше пример - void test() вызванный как test(1) компилится (и даже работает), а void test(void) - нет.

    ОтветитьУдалить
  18. Анонимный16/10/07 14:04

    А какая версия gcc?

    А что будет для такого кода?

    void test(){}
    int main(){
    test(1,'a');
    return 0;
    }

    ОтветитьУдалить
  19. Анонимный16/10/07 14:07

    Интересно как можно получить доступ к аргументу такой функции как void test();? Через va_list?

    ОтветитьУдалить
  20. 3.4.4, cygwin
    Компилится, запускается.
    Да, через va_list, видимо.

    ОтветитьУдалить