Re: Чёртов язык Си!
On Tue, 7 Oct 2014, Artem Chuprina wrote:
yuri.nefedov@gmail.com -> debian-russian@lists.debian.org @ Tue, 7 Oct 2014 18:16:32 +0400 (MSK):
>> y> В С нет разницы между void f(struct S a[]) и void f(struct S *a)
>> y> - компилятору это всё равно.
>> y> Моё беспокойство было, как будет обрабатываться a[i] или, что то же
>> y> самое *(a+i). Как компилятор предотвратит использование такой
>> y> конструкции?
>>
>> Я полагаю, скажет "incomplete type" и обломает компиляцию.
y> Мы говорим об одном и том же. По стандарту языка С
y> incomplete type == types that describe objects but lack information
y> needed to determine their sizes
y> Тогда похоже, что между указателями на incomplete type и void*
y> вообще нет никакой разницы. Тем более что и преобразования
y> типа void* <-> struct* будут выполнятся молча, даже без
y> предупреждений. Просто это «сахар» для писателя/читателя программы.
y> Можно было бы и typedef обойтись.
Между void * и struct *, может, и без предупреждения. А между struct A * и struct B *?
---- test.c ----
struct S0;
struct S1;
void f (struct S0 *p) {}
int main (int argc, char **argv) {
f((struct S1 *)0);
}
----------------
zsh% gcc -c test.c
test.c: In function ‘main’:
test.c:7:12: warning: passing argument 1 of ‘f’ from incompatible pointer type [enabled by default]
test.c:4:6: note: expected ‘struct S0 *’ but argument is of type ‘struct S1 *’
Ну и дальше по вкусу.
Вообще говоря это warnings, то есть код компилируется (.
Надо сказать, что С весьма непоследователен в части
преобразования типов. Скажем:
int* a = NULL;
double* b = NULL;
a = b; // warning: incompatible pointer types assigning to 'int *' from
'double *'
а если сделать:
void* tmp = b;
a = tmp;
то никаких предупреждений не будет, а при оптимизации и tmp
пропадет.
Возвращаясь же к примеру, мое предложение было написать что-то типа
typedef void* struct_S_ptr;
и вызывать
f((struct_S_ptr)0);
И предупреждений не будет и читаемость сохранится.
Все вместе последовательно:
Имеется библиотека с прототипами функций вида
f (struct S0 *p,...)
1) Можно определить переменные с не полностью определенным типом
struct S0 *a, *b, *c;
и использовать их.
2) Можно использовать
void *a, *b, *c;
и поменять прототипы на
f (void *p,...)
Линкуется и работает все замечательно.
Когда сам попробовал, то выяснилось что второй путь
крайне мутный, хотя и работает. Лучше так не делать.
Ю.
Reply to: