Потому что в Си можно отличить вызов функции без параметров от ее объявления по void в качестве параметра
я специально написал вам параметр int, чтобы вы обратили внимание на void, но вы не обратили... а речь шла по этому поводу:
Reflector писал(а):
Если грамматика языка допускает пустоту вместо ключевого слова означающего пустоту, то разумно void просто исключить.
если можно опускать void для обозначения пустоты, то надо и в прототипе функции опускать тип void. однообразно, как в армии
Reflector писал(а):
А с void в начале все однозначно в обоих языках
однозначно ЕСТЬ, но, имхо, не однозначно - НАФИГА?
Reflector писал(а):
Именно, это будет разыменование указателя вместо объявления переменной типа void*
да, в системе координат искаженной логики, как сейчас. но могло бы быть просто: если нет присваивания переменной, то это ее объявление. если есть присваивание - это ее использование. и было бы так:
Код:
int var; // объявление переменной типа int int* iptr; // объявление указателя на int-переменную iptr = &var; // использование переменных * var2; // объявление "абстрактного" указателя var2 = &var; // использование iptr = (int*)var2; // использование var2 var = *var2; // это ошибка, т.к. разыменование абстрактного указателя не разрешено (хотя почему, если он совместим с char*?)
по-моему, эти записи МОГЛИ БЫ быть вполне однозначно читаемы без всяких оговорок. в существующей парадигме языка используется странное слово void для обозначения "абстрактного указателя", хотя сама звездочка без добавок могла бы это обозначать.
то есть форма записи не важна. важен смысл, который вкладывается в форму. и вот с ТИПОМ VOID имеется некое соответствие между формой и смыслом. но я снова повторяюсь...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
То есть пустота/ничто в данных БД и даже в переменных Вас устраивает, а в С нет? Как-то не последовательно получается.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Сумеете создать переменную этого класса (С++)? Все отличие от void что последний может быть аргументом и результатом функции.
Цитата:
да, в системе координат искаженной логики, как сейчас. но могло бы быть просто: если нет присваивания переменной, то это ее объявление. если есть присваивание - это ее использование. и было бы так:
Код:
int var; // объявление переменной типа int int* iptr; // объявление указателя на int-переменную iptr = &var; // использование переменных * var2; // объявление "абстрактного" указателя var2 = &var; // использование iptr = (int*)var2; // использование var2 var = *var2; // это ошибка, т.к. разыменование абстрактного указателя не разрешено (хотя почему, если он совместим с char*?)
*var2 это разыменование указателя? Или указатель на неявный int по аналогии с signed *var2; ? . И, хоть вы меня так упорно игнорируете повторю вопрос. Вы правда считаете что было бы логично вместо функции в общем виде ввести 4 отдельных разновидности?
я стараюсь не возобновлять старый спор, поскольку у нас была договоренность его прекратить.
COKPOWEHEU писал(а):
Сумеете создать
я крайне плохо знаю С++, настолько плохо, что вот вообще сейчас не понял, чего вы от меня хотите и о чем вот это сказано
COKPOWEHEU писал(а):
Все отличие от void что последний может быть аргументом и результатом функции
может, тут что-то пропущено? не понимаю вообще - набор слов
COKPOWEHEU писал(а):
*var2 это разыменование указателя? Или указатель на неявный int по аналогии с signed *var2; ?
я постоянно говорю, что в Си много всяких странностей и противоречий. но уделяю внимание я только частностям. вы вынуждаете меня раскрыть все карты ну что ж... неявные указания типов и тому подобные "умолчания" я считаю так же источником "внутреннего напряжения".
вы должны понять, что нельзя пытаться убрать только одно из многих странных мест языка и получить в итоге стройный и идеальный язык. поэтому не логично спрашивать, почему все плохо осталось, если принять какую-то одну мою концепцию. если все остальные догматы языка Си остаются неизменными, то смысл записи *var в моей системе координат действительно непросто идентифицировать, примерно так же, как не понятен смысл слова void в случае применения его в качестве типа данных.
с моей точки зрения язык программирования должен иметь синтаксис и правила построения конструкций такие, чтобы не было никаких недосказанностей, умолчаний, подразумеваний, зависимости смысла конструкции от контекста применения и т.п. неоднозначностей. то есть если определено правило "описание переменной - это запись формата <тип> <список идентификаторов>;", то чтобы никогда и ни при каких ситуациях из этого правила не было исключений. чтобы не было "синонимов" типа "int == signed" или чего-то подобного. нет, если стандарт допускает определение пользовательских типов, то такие "синонимы" могут быть результатом реализации мыслей программиста, но никак не "вольностями" стандарта. чтобы раз уж определен формат "прототипа функций", то абсолютно всегда и в любых контекстах он был неизменным вплоть до символа. никаких "можно не писать" или "подразумевается". если в одном месте разрешено в качестве истинного условия использовать пустое место - это пустое место должно быть разерешно в качестве замены "истины" во всех местах - от if до присваивания (т.е. если for(;;) - это корректно, обязано быть корректным и _Bool b =; т.е. b==true). ну или наоборот - везде запрещено, и тогда никаких for(;;) быть не должно в принципе.
примерно так должно быть в идеальном с моей т.з. языке.
поскольку идеального в мире нет вообще, мне просто хотелось бы максимального приближения к нему всегда, когда это возможно. в частности, я пытаюсь решить эту проблему внутри Си для себя так: я сознательно исключаю из обихода часть стандартных фич, считая их неприемлемыми - ну, типа _Bool. или вот я стараюсь вообще не использовать int или char, как типы формально неизвестного размера, и заменяю их на uint8_t или int16_t (получая при этом варнинги о несоответствии типов при работе с libc). когда примерно 50% стандарта выбросишь, и делаешь вид, что их просто нет, а то, что они разрешали - запрещено, сразу получается существенно меньшее поле для граблей и проблем. только возникает неприятие чужого кода из-под рук адептов "полного стандарта".
вы на самом деле считаете, что подразумеваемые типы - это хорошо? что это упрощает понимание кода? вы на самом деле считаете, что нет противоречия в подходах между while(1) и for(;;) ? и подобных случайностей море - от неизвестного размера int до неизвестного знака у char. что же это за "стандарт" в котором [почти] все, что не разрешено - допустимо?!
используя Си я ощущаю себя бреющимся тупым ржавым лезвием: не удобно, не приятно, можно изуродоваться, но ничего другого лучше нет под рукой...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Не убий - хороший принцип, но не тогда, когда на Ваших глазах насилуют Вашу дочь. Не укради - хороший принцип, но не тогда, когда выкрав секрет у врага Вы спасете планету от ядерной войны. Не солги - хороший принцип, но не тогда, когда Вы говорите умирающему, что он поправится. Почитай отца своего - хороший принцип, но не тогда, когда он в алкогольном угаре хочет убить Вашу мать.
В свое время святые отцы утверждали что РАССУДИТЕЛЬНОСТЬ - величайшая добродетель.
Ну раз прекратить это безобразие не получактся, то может быть, для этих умствований создать отдельеую ветку "Спор высокоумных тетеретиков ни об чем", перенести туда этот флейм, и пусть там грызутся ? Форум наш радиолюбительский, и филиал РАН тут как-то не совсем. Я так думаю.
Вы уж простите, но это не так. У указателеля тоже может быть тип, определяющий, прямо или косвенно, размер этого указателя в байтах. Или, для Гарвардской архитектуры, на какую область памяти он указывает: программы или данных. В стандарте C11 про все эти far, long far, near, __flash, PROGMEM и т.п. нет ни слова. Но в конкретных компиляторах они еще как есть.
WiseLord писал(а):
будет лучше воспринят, если записать его, приблизив звёздочку к типу: Но тут нужно быть осторожным, и не попасться в ловушку вроде:
Код:
char* ptr1, ptr2, ptr3;
Я именно из-за такой ловушки и сам всегда пишу звездочку вплотную к указателю, и настаиваю, чтобы это было указано в регламенте разработки. Особенно невнятна такая запись при указателе на указатель в выражении. Так, IMHO, читабельней:
Код:
char a=1, b=2, c; char *ptr1; char **ptr2;
ptr1 = &a; ptr2 = &ptr1;
c = b * **ptr2;
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
вот еще нюансик Си, о котором я никогда сам не упоминал. всего-навсего вопрос существует ли тип char * или нет. Спойлер
ptr128 писал(а):
Аlex писал(а):
У указателя нет своего типа
Вы уж простите, но это не так. У указателеля тоже может быть тип, определяющий, прямо или косвенно, размер этого указателя в байтах. Или, для Гарвардской архитектуры, на какую область памяти он указывает: программы или данных. В стандарте C11 про все эти far, long far, near, __flash, PROGMEM и т.п. нет ни слова. Но в конкретных компиляторах они еще как есть.
WiseLord писал(а):
будет лучше воспринят, если записать его, приблизив звёздочку к типу: Но тут нужно быть осторожным, и не попасться в ловушку вроде:
Код:
char* ptr1, ptr2, ptr3;
Я именно из-за такой ловушки и сам всегда пишу звездочку вплотную к указателю, и настаиваю, чтобы это было указано в регламенте разработки. Особенно невнятна такая запись при указателе на указатель в выражении. Так, IMHO, читабельней:
Код:
char a=1, b=2, c; char *ptr1; char **ptr2;
ptr1 = &a; ptr2 = &ptr1;
c = b * **ptr2;
просто если существует именно тип char * (или любой иной указатель), то весь список переменных должен быть именно этого типа, точно так же, как как int a, b, c; - все три переменные одного типа int. получается, что не существует типа char*... тогда как объяснить существование явного приведения типа (char*)ptr? я к тому, что в описании переменных все, что левее списка идентификаторов переменных - это тип их данных. это правильная формулировка или нет? в стандарте так написано или, как обычно, что-то вроде "нужно так, но если хочется - можно иначе, а в некоторых случаях еще и по-другому, а для вот этого случая нужно вообще не так".
снова противоречие в логике построения синтаксически корректных конструкций или нет никакого противоречия и все логично?
будет ли корректной такое описание трех указателей?
Код:
char *ptr1, *ptr2, *ptr3;
если да, то что скажете на предположение о том, что звездочка в данном контексте полный синоним по смыслу слова "указатель"?
Добавлено after 12 minutes 19 seconds: Re: Продолжение боёв по теме _Bool, void и всякой квантовой физике сам убедился, что запись будет корректной. более того, 100% корректной будет и такая запись
Код:
*ptr1, *ptr2, *ptr3;
только по умолчанию они будут указателями на int
выходит, никаких препятствий отказаться от void при описании абстрактного указателя нет, достаточно стандартизировать "особые" умолчания для указателей...Спойлеря вот о таком подходе: типы описываемых переменных (списков переменных): int, char, long и т.п. - целочисленные float, double - плавучие ... * - абстрактный указатель, совместимый с указателем на char int*, char*, long* и т.п. - типизованные указатели на заданные типы данных или опять моя логика некорректна?
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
я специально написал вам параметр int, чтобы вы обратили внимание на void, но вы не обратили...
Синтаксис должен быть единообразным, т.е. если одна функция ничего не принимает и не возвращает, а другая принимает, но тоже не возвращает, то void для указания типа возвращаемого значения должен присутствовать или отсутствовать в обоих случаях.
Цитата:
int* iptr; // объявление указателя на int-переменную iptr = &var; // использование переменных * var2; // объявление "абстрактного" указателя var2 = &var; // использование iptr = (int*)var2; // использование var2 var = *var2; // это ошибка, т.к. разыменование абстрактного указателя не разрешено (хотя почему, если он совместим с char*?)[/code]
Сейчас можно написать void *p = 0;, ты предлагаешь оставить *p = 0; и тогда непонятно это просто присвоение для уже существующей переменной или присвоение совмещенное с объявлением.
Может быть для разнообразия на Perl переключимся? Там вообще нет функций, только процедуры. Но зато любая процедура может вернуть любое количество (в том числе и пустое) значений любого типа. То есть, любая процедура может быть вызвана, как функция. И, в зависимости от параметров вызова, может быть или функцией, или процедурой
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
ты предлагаешь оставить *p = 0; и тогда непонятно это просто присвоение для уже существующей переменной или присвоение совмещенное с объявлением
согласен, этот момент не учел. но мне кажется, при желании, этот момент может быть решен довольно просто... если первое вхождение в тексте переменной - то это объявление с присваиванием, не первое - присваивание уже существующей. собственно, как и должно быть... в конце концов можно и пробелом сыграть: есть пробел между * и идентификатором - это описание переменной типа "абстрактный указатель", нет пробела - разыменование (блин, и кто придумал этот термин?! и язык, и пальцы сломаешь, и смысл какой-то странный... при чем тут имя, если речь про доступ к данным по указателю?).
ptr128 писал(а):
для разнообразия на Perl переключимся?
переключайтесь, если вы ждали моего разрешения
Reflector писал(а):
Синтаксис должен быть единообразным
вот, блин, о чем я и толкую все время!!! если допустимо for(;;), то должно быть допустимо и if() и while(). если только допустимо while(1), то только for(;1;) и if, как сейчас. и остальное-прочее в том же духе по всем вопросам
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Но тут нужно быть осторожным, и не попасться в ловушку вроде:
Код:
char* ptr1, ptr2, ptr3;
Ибо может сложиться впечатление, что тут объявлены три указателя на char, но на самом деле указатель один (ptr1), а (ptr2 и ptr3) - это просто char-ы.
Вот это точно ловушка, в которую я мог угодить. Для правильности и однозначности (не только здесь) действительно лучше писать раздельно.
ptr128 писал(а):
Аlex писал(а):
У указателя нет своего типа
Вы уж простите, но это не так. У указателеля тоже может быть тип, определяющий, прямо или косвенно, размер этого указателя в байтах.
Размерность есть, но ведь она нигде не объявляется? Она только определяется размерностью адреса конкретного железа.
ptr128 писал(а):
Код:
char **ptr2;
Указатель на указатель?
ptr128 писал(а):
Код:
c = b * **ptr2;
С ума сойти можно. b умножить на нечто, адрес которой содержится в указателе, на который указывает Указатель2. Так ведь получается? Тогда для однозначности и наглядности лучше написать c = b * (**ptr2)
_________________ Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
ты предлагаешь оставить *p = 0; и тогда непонятно это просто присвоение для уже существующей переменной или присвоение совмещенное с объявлением
согласен, этот момент не учел. но мне кажется, при желании, этот момент может быть решен довольно просто... если первое вхождение в тексте переменной - то это объявление с присваиванием, не первое - присваивание уже существующей. собственно, как и должно быть... в конце концов можно и пробелом сыграть: есть пробел между * и идентификатором - это описание переменной типа "абстрактный указатель", нет пробела - разыменование
Допустим программист встречает следующий код:
Код:
*a = 0; *b = 0;
Вряд ли он обрадуется если эти две с виду одинаковые строки означают совершенно разные вещи, потому что одна из этих переменных уже где-то объявлена.
ARV писал(а):
вот, блин, о чем я и толкую все время!!! если допустимо for(;;), то должно быть допустимо и if() и while(). если только допустимо while(1), то только for(;1;) и if, как сейчас. и остальное-прочее в том же духе по всем вопросам
Ладно, добавят тебе в Си if(), для чего его можно будет использовать?
У указателеля тоже может быть тип, определяющий, прямо или косвенно, размер этого указателя в байтах.
Размерность есть, но ведь она нигде не объявляется? Она только определяется размерностью адреса конкретного железа.
Далеко не всегда. МК может поддерживать одновременно 16, 24 и 32 битные указатели. Их старшие собратья (CPU) могут поддерживать так же 48 и 64 битные указатели. Например, STM8 использует и 16, и 24 битную адресацию. На AVR в GCC это сделано искусственно http://www.atmel.com/webdoc/AVRLibcRefe ... 05s01.html
Zhuk72 писал(а):
ptr128 писал(а):
Код:
char **ptr2;
Указатель на указатель?
Ну да. А почему бы и нет?
Zhuk72 писал(а):
ptr128 писал(а):
Код:
c = b * **ptr2;
b умножить на нечто, адрес которой содержится в указателе, на который указывает Указатель2. Так ведь получается? Тогда для однозначности и наглядности лучше написать c = b * (**ptr2)
Все правильно, и Ваша запись более наглядная. Я же приводил пример, в качестве возражения, предоложению отделять * от имени указателя.
_________________ Не ошибается только то, кто ничего не делает. Тот, кто признает свои ошибки, на них учится. Глупец же, упорствуя в своих заблуждениях, остается глупцом.
я крайне плохо знаю С++, настолько плохо, что вот вообще сейчас не понял, чего вы от меня хотите и о чем вот это сказано
Объявление абстрактного типа. Его особенность в том, что им напрямую невозможно пользоваться - ни создавать переменных, ни принимать, ни возвращать (что, на мой взгляд, странно). Зато от него можно производить не-абстрактные наследные классы, работа с которыми ничем не примечательна.
Цитата:
может, тут что-то пропущено? не понимаю вообще - набор слов
в свете предыдущего: невозможно создать переменную абстрактного типа (что AbsClass из моего примера, что void). Но void, в отличие от AbsClass, можно передавать и принимать в функцию. В Си абстрактных типов, кроме void, нет, так что все нормально. А вот в ООП-языках возникает другое противоречие.
Цитата:
вы должны понять, что нельзя пытаться убрать только одно из многих странных мест языка и получить в итоге стройный и идеальный язык. поэтому не логично спрашивать, почему все плохо осталось, если принять какую-то одну мою концепцию
Если принять все ваши концепции - получится Паскаль
Цитата:
чтобы не было "синонимов" типа "int == signed" или чего-то подобного
на самом деле в Си еще хуже - int может быть как знаковым, так и беззнаковым да еще и произвольного размера, лишь бы не меньше char. Впрочем, вот это вы наверняка и так знали.
Цитата:
пустое место должно быть разерешно в качестве замены "истины" во всех местах - от if до присваивания (т.е. если for(;;) - это корректно, обязано быть корректным и _Bool b =; т.е. b==true)
for - довольно интересный оператор. Он ведь принимает не какой-то конкретный тип данных, а выражения. Скажем, в записи for(i=0,j=1;i==0;i+=j,j--){} какой тип данных у каждого аргумента?
Цитата:
вы на самом деле считаете, что подразумеваемые типы - это хорошо? что это упрощает понимание кода? вы на самом деле считаете, что нет противоречия в подходах между while(1) и for(;;) ? и подобных случайностей море - от неизвестного размера int до неизвестного знака у char. что же это за "стандарт" в котором [почти] все, что не разрешено - допустимо?!
Нет, подразумеваемыми типами я тоже стараюсь не пользоваться. Если не ошибаюсь, их и оставили только для совместимости со старыми версиями - не даром компилятор на такое ругается. Неизвестный размер и знак у стандартных типов - дань универсальности. На AVR удобнее взять для int 2 байта, на x86 - 4 байта, а на x64 - 8 байт. При этом для многих целей достаточно и 2-байтного int, но городить лишний код, на 4-байтном int, который обеспечивал бы переполнение после 0xFFFF, вместо автоматического 0xFFFFFFFF, не надо. Ну а если хочется иметь фиксированный размер - (u)intX_t и явное приведение типов в помощь.
не знаю, как в последних версиях, но когда я с этим вопросом разбирался, я пришел к выводу, что в avr-gcc не то, что сделали криво, а вообще не сделали никак. потому что основная польза указателя - в его "автоматическом" использовании, т.е. присваивании ему адреса оператором & и разыменовании его операторами * или ->. с uint_farptr_t этот номер закономерно не проходит.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Сейчас этот форум просматривают: Coyote2025, Majestic-12 [Bot] и гости: 64
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения