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

Статья Reading C type declarations

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

int (*(*)())()

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

20 коммент.:

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

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

Nunquam dormio комментирует...

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

Nunquam dormio комментирует...

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

Nunquam dormio комментирует...

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

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

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

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

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

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

Алёна комментирует...

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

Не очень поняла, что значит "типы аргументов не определены". Там две функции, обе без аргументов.
Вообще 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'

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

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

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

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

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

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

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

;) sse

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

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

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) - нет.

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

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

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

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

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

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

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

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