[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: