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

Статья Reading C type declarations

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

int (*(*)())()

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

20 коммент.:

Алексей комментирует...

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

CyberZX комментирует...

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

CyberZX комментирует...

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

CyberZX комментирует...

то есть эквивалентно такому коду

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

Алексей комментирует...

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

migmit комментирует...

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

Alena комментирует...

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

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

Алексей комментирует...

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

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

Анонимно комментирует...

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

migmit комментирует...

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

migmit комментирует...

Чтобы было понятнее:
$ 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'

Анонимно комментирует...

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

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

Анонимно комментирует...

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

Анонимно комментирует...

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

;) sse

Анонимно комментирует...

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

Анонимно комментирует...

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

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

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

Или я не прав?

migmit комментирует...

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

Анонимно комментирует...

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

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

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

Анонимно комментирует...

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

migmit комментирует...

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