LINUX.ORG.RU
ФорумTalks

Через три дня должен выйти GCC 11.2

 ,


0

1

Первый RC уже анонсирован:

https://gcc.gnu.org/pipermail/gcc/2021-July/236837.html

Размер незапакованного патча порядка 57 мегабайт. Список изменений я не нашёл.

Перемещено xaizek из development



Последнее исправление: hummer (всего исправлений: 1)
Ответ на: комментарий от firkax
assert(argc >= 0);
size_t right_argc = static_cast<size_t>(argc);
// дальше использовать только right_argc
fsb4000 ★★★★★
()
Ответ на: комментарий от firkax

А индекс должен быть size_t.

Кто-то видимо не знает историю того, почему в STL у C++ затесался size_t (что многие до сих пор считают ошибкой), тогда как в Qt и Java сделали ставку на signed индексы и не прогадали.

Споры по этому поводу выбора unsigned в STL до сих пор бурлят в интернете: https://github.com/ericniebler/stl2/issues/182#issuecomment-257000171

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от dsdqmhsx

А, походу я напутал. Речь была про -Wparentheses, это когда рекомендует дополнительные скобки в строках вида if(a=b). Тут и правда логично предупреждать, хотя лично мне не нужно. А про скобки в логических выражениях это из -Wall да, они мне оба не нравились вот и забыл какое откуда.

Ну извините тогда.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Давай, ты не будешь думать что ты умнее всех.

EXL ★★★★★
()
Ответ на: комментарий от firkax

включёные по дефолту идиотские варнинги о рекомендации писать (A&&B)||C вместо A&&B||C и ещё какие-то (не помню) — создают впечатление что оно сделано для умственно отсталых

Знаю, что силанг советуют из-за более удобных сообщений об ошибках, думаю оттуда ноги растут.

fernandos ★★★
()
Ответ на: комментарий от firkax

Если ты программируешь не раз в год, то порядок таких постоянно используемых операций сам собой очень быстро запоминается

Был схожего мнения про блокировку файла, пока несколько раз не встречал исключительную блокировку для чтения. Если компилятор может сделать что-то для повышения безопасности/снижения количества багов, пускай это и делает.

fernandos ★★★
()
Ответ на: комментарий от EXL

Почему он в STL C++ я никогда не интересовался.

В Си size_t нужен как тип, гарантированно достаточный для обозначения индекса в любом непрерывном массиве в памяти. И для такого языка это необходимо.

Разумеется, не всё так однобоко, и unsigned числа имеют и недостатки - в виде, например, неожиданной в бытовом плане математики 10-15=251. Поэтому для скриптовых и около того языков лучше сделать всем понятные знаковые типы для всего, а издержек синтаксического мусора и прочего оверхеда там и так столько, что лишние проверки >=0 особой погоды не сделают. В Си же эта математика - отражение реальной логики работы железа - как раз необходима в ряде случаев. Иными словами, если вам трудно работать с низкоуровневыми типами и не нужна их эффективность - пишите себе на джаве и не парьтесь.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Затем что сувание signed int туда, где отрицательных чисел в принципе быть не должно - чуть (в данном случае незаметно, да, но всё равно неприятно) уменьшает скорость работы кода (сравни ассемблер для деления на 2 для unsigned и singed), чуть увеличивает вероятность багов (этого видел огромное количество на практике, хотя да не с argc, а с другими переменными, и не в своём коде) и уменьшает общую прозрачность и эстетичность кода.

Что за глупости ты сейчас написал? Зачем тебе вообще делить argc на два, да ещё так сильно переживая о производительности? Есть стандартный ABI и в нём argc - это просто int, который по умолчанию signed. Ни у кого это проблем не вызывает, даже эстетических, а у тебя почему-то зудит.

P.S. В Java вообще отказались от unsigned типов, кроме разве что char, который аналогичен unsigned short. Впрочем char ни для какой арифметики обычно не применяется. В большенстве случаев unsigned вреден, увеличивает вероятность багов и кроме как в каком-то системном коде использоваться не должен.

hummer
() автор топика
Ответ на: комментарий от burato

Можно, но ядро и мир им не откомпилируешь - нужно исправить исходники, на которые ругается компилятор. Ещё библиотеки времени выполнения и линковщик (ld) поменять на GCC’шные.

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 1)
Ответ на: комментарий от hummer

Просто пиши на джаве.

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

Тебе наверно бесполезно что-то отвечать, но чтобы никто из читателей не был введён в заблуждение твоими глупостями, и чтобы моё сообщение не выглядело оффтопом, прокомментирую:

«ABI» (B = binary) signed и unsigned int отличаются только представлением чисел, выходящих за пределы представления положительных чисел signed int’а. Других чисел в этот аргумент передавать всё равно нельзя. Так то с ABI всё в порядке.

«unsigned вреден, увеличивает вероятность багов» только для тех, кто не понимает что это такое. Если интуитивно понимать, что unsigned int 10-15=251 (или другое положительное число, взависимости от типа), считать это не каким-то исключением или странностью, а рядовой математикой, то никаких проблем нет. А те, кто вышеописанное осилить не в состоянии, на мой взгляд, не должны писать на Си ничего, кроме учебного кода или каких-то личных мелочей.

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

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 4)
Ответ на: комментарий от hummer

Что, лицензия GNU запрещает использовать GCC в лицензированной под BSD системе?

hateWin ★☆
()
Ответ на: комментарий от firkax

Просто пиши на джаве.

Ну наконец-то! Спасибо, что разрешил.

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

Я писал и на ассемблере и на C. Жаль, что у тебя нет никаких иных аргументов, кроме как писькомерство.

«ABI» (B = binary) signed и unsigned int отличаются только представлением чисел, выходящих за пределы представления положительных чисел signed int’а. Других чисел в этот аргумент передавать всё равно нельзя. Так то с ABI всё в порядке.

И потом ты захочешь вызвать функцию getopt(), которая ожидает всё тот же signed int, но ты же самый умный и у тебя unsigned int.

«unsigned вреден, увеличивает вероятность багов» только для тех, кто не понимает что это такое. Если интуитивно понимать, что unsigned int 10-15=251 (или другое положительное число, взависимости от типа), считать это не каким-то исключением или странностью, а рядовой математикой, то никаких проблем нет. А те, кто вышеописанное осилить не в состоянии, на мой взгляд, не должны писать на Си ничего, кроме учебного кода или каких-то личных мелочей.

Не только интуитивно, но и объективно ты ламер и не понимаешь что это такое, потому что заявленное тобой: «unsigned int 10-15=251» является очевидной ложью. Следующий код напечатает 4294967291, а не 251.

#include <stdio.h>

int main()
{
    unsigned int a = 10;
    unsigned int b = 15;
    unsigned int c = a - b;
    
    printf("%u\n", c);

    return 0;
}

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

Это дело как раз таки компилятора, потому что речь идёт не просто о какой-то там функции, а о функции, сигнатура которой прописана в стандарте. То есть в общем случае у неё не может быть любой прототип, а лишь тот, который или которые разрешены стандартом.

hummer
() автор топика
Ответ на: комментарий от hummer

Я писал и на ассемблере и на C. Жаль, что у тебя нет никаких иных аргументов, кроме как писькомерство.

Это не писькомерство, а допуск к обсуждению, дабы отсеять тех кто явно не в теме. Удивительно как ты писал если не понимаешь таких очевидных вещей.

И потом ты захочешь вызвать функцию getopt(), которая ожидает всё тот же signed int, но ты же самый умный и у тебя unsigned int.

Туда просто перекочевала эта глупость с signed int. Ну а вообще прекрасно она работает с unsigned, если числа меньше чем максимум int’а. Хотя должна, конечно же, с size_t, если по уму делать.

Не только интуитивно, но и объективно ты ламер и не понимаешь что это такое, потому что заявленное тобой: «unsigned int 10-15=251» является очевидной ложью. Следующий код напечатает 4294967291, а не 251.

Речь шла про unsigned типы вообще, как пример был приведён char. Слово int туда попало по недосмотру (а редактировать уже было поздно), и по-моему это очевидно, но нет, надо придраться.

Это дело как раз таки компилятора, потому что речь идёт не просто о какой-то там функции, а о функции, сигнатура которой прописана в стандарте. То есть в общем случае у неё не может быть любой прототип, а лишь тот, который или которые разрешены стандартом.

Ну ты один из тех религиозно-стандартных фанатиков, таких же как те что всунули эту гадость в clang. Прототип fopen() тоже в стандарте прописан, но тебе никто не помешает сделать свой fopen() с другим прототипом. Потому что одно дело синтаксис языка и правила трансляции языковых конструкций в машинные инструкции - они заложены в компиляторе и не могут меняться программистом. Другое дело библиотека - её можно хоть написать свою, хоть не использовать вовсе.

Стандарт, в случае Си, это не первоисточник абсолютной истины, а всего лишь подведение итогов по поводу сложившихся общепринятых практик (на общепринятых платформах) на момент конца 80-х годов (С99 и более поздние - так вообще скорее рекомендации по поддержке новых фич для авторов компиляторов). И если синтаксис языка от платформы не зависит и везде одинаковый (почти), то интерфейс к загрузчику и прочим частям системы - платформенно-специфичный. В винде вот например нет main() вообще, там есть WinMain(). Так же где-то запросто может не быть stdio.h или других частей стандартной библиотеки, это никак не адекватное основание отказаться компилировать этот код.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Это не писькомерство, а допуск к обсуждению, дабы отсеять тех кто явно не в теме. Удивительно как ты писал если не понимаешь таких очевидных вещей.

Ну ты мне ещё допуски начни раздавать. :-))) Удивительно, как ты умудрялся работать в команде с такими закидонами или ты одиночка?

Туда просто перекочевала эта глупость с signed int. Ну а вообще прекрасно она работает с unsigned, если числа меньше чем максимум int’а. Хотя должна, конечно же, с size_t, если по уму делать.

Ну вот ты так вольно обращаешься с типами, полагаясь лишь на то, что argc врядли переполнится, но в каком-то другом месте это может вызвать проблему. И всё это непонятно ради чего, да ещё с таким апломбом и возмущением.

Речь шла про unsigned типы вообще, как пример был приведён char. Слово int туда попало по недосмотру (а редактировать уже было поздно), и по-моему это очевидно, но нет, надо придраться.

По недосмотру ты можешь и код с таким же неправильным предположением написать. Поэтому лучше, когда компилятор заранее даст тебе по рукам, чтобы ты не выпендривался. :-))

Ну ты один из тех религиозно-стандартных фанатиков, таких же как те что всунули эту гадость в clang. Прототип fopen() тоже в стандарте прописан, но тебе никто не помешает сделать свой fopen() с другим прототипом. Потому что одно дело синтаксис языка и правила трансляции языковых конструкций в машинные инструкции - они заложены в компиляторе и не могут меняться программистом. Другое дело библиотека - её можно хоть написать свою, хоть не использовать вовсе.

В отличии от fopen() прототип main() нельзя изменить. А ты, надо полагать, один из тех кулхацкеров, кто балуется ранней оптимизацией кода.

Стандарт, в случае Си, это не первоисточник абсолютной истины, а всего лишь подведение итогов по поводу сложившихся общепринятых практик (на общепринятых платформах) на момент конца 80-х годов (С99 и более поздние - так вообще скорее рекомендации по поддержке новых фич для авторов компиляторов). И если синтаксис языка от платформы не зависит и везде одинаковый (почти), то интерфейс к загрузчику и прочим частям системы - платформенно-специфичный. В винде вот например нет main() вообще, там есть WinMain(). Так же где-то запросто может не быть stdio.h или других частей стандартной библиотеки, это никак не адекватное основание отказаться компилировать этот код.

Стандарт, как и общепринятые практики - это то, на что нужно ориентироваться. Например Google, в своём style guide прямым текстом не рекомендует использовать unsigned типы, кроме как в отдельных, весьма редких случаях. Почитай на досуге. А в Винде есть и main() и WinMain() и даже DllMain(), а какой из них будет entry point решает линкёр - либо сам, либо в соответствии с параметрами линковки.

hummer
() автор топика
Последнее исправление: hummer (всего исправлений: 1)
Ответ на: комментарий от hummer

Удивительно, как ты умудрялся работать в команде с такими закидонами или ты одиночка?

Ну, в команде с такими как ты я точно не стал бы работать.

Ну вот ты так вольно обращаешься с типами, полагаясь лишь на то, что argc врядли переполнится, но в каком-то другом месте это может вызвать проблему.

Проблемы вызывает расчёт кода на отрицательные числа там, где их быть не должно. И, повторюсь, такие баги я видел (в публичном популярном софте) и не один раз. В том числе и потому, что переполнение signed int наступает в два раза раньше того, что могло бы быть, а unsigned даже если переполнится, то во многих (не во всех - и программист разумеется должен это всё предусматривать) случаях это произойдёт прозрачно и без багов (не надо делать спец. ветки кода для обработки).

По недосмотру ты можешь и код с таким же неправильным предположением написать. Поэтому лучше, когда компилятор заранее даст тебе по рукам, чтобы ты не выпендривался. :-))

Ошибки конечно у всех бывают, но сравнивать не надо. Код многократно перепроверяется перед попаданием в рабочую версию.

В отличии от fopen() прототип main() нельзя изменить.

Это в дурацком clang-е нельзя. А так, разумеется, можно. И разницы вобщем-то никакой - и то и то это всего лишь соглашение с используемой libc. Только fopen() это предоставляемая библиотекой функция, а main() - вызываемый из библиотеки колбек (ну, почти).

Стандарт, как и общепринятые практики - это то, на что нужно ориентироваться.

Если других источников ориентации нет - то остаётся только так, да. Но это ж не всегда так.

Google

Плевать.

style guide

Тем более что оно не про Си.

А в Винде есть и main() и WinMain() и даже DllMain(), а какой из них будет entry point решает линкёр - либо сам, либо в соответствии с параметрами линковки.

Хорошо, перефразирую - в «win32 native проге с стандартной ms библиотекой есть WinMain и нету main». А entry point не будет ни одно из них. Entry point - в статически слинкованной части rtl, он уже, среди прочего, вызывает одну из этих трёх обычных функций. Да, можно перенастроить линкер чтобы он сделал entry point’ом какую-то самописную функцию, но обычно так не делают. И argc argv ей точно никто не передаст, она должна будет сама их получать с помощью winapi.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ну, в команде с такими как ты я точно не стал бы работать.

Да ты вообще в команде работать не можешь.

Проблемы вызывает расчёт кода на отрицательные числа там, где их быть не должно. И, повторюсь, такие баги я видел (в публичном популярном софте) и не один раз. В том числе и потому, что переполнение signed int наступает в два раза раньше того, что могло бы быть, а unsigned даже если переполнится, то во многих (не во всех - и программист разумеется должен это всё предусматривать) случаях это произойдёт прозрачно и без багов (не надо делать спец. ветки кода для обработки).

Целочисленное переполнение возникает либо из-за неправильной реализации алгоритма, либо из-за недостаточной разрядности числа (и речь вовсе не о недостатке в один сраный бит). Ни в первом ни во втором случае unsigned не является панацеей и нужно либо исправлять алгоритм кода, либо переходить на long или long long (в зависимости от дата модели LP64 или LLP64). Твоё утверждение о том, что целочисленное переполнение unsigned менее болезненно, чем signed - просто враньё.

Ошибки конечно у всех бывают, но сравнивать не надо. Код многократно перепроверяется перед попаданием в рабочую версию.

Ещё как надо сравнивать, потому что в таком лихом и плохочитаемом кода такая бага может сидеть незамеченной годами. Статическую типизацию придумали как раз для выявления как можно большего числа подобных проблем на этапе компиляции, но ты считаешь себя умнее и просто отключаешь надоедливые предупреждения компилятора о несоответствии типов.

Это в дурацком clang-е нельзя. А так, разумеется, можно.

Да что ты говоришь? Ты вообще знаешь, что такое прототип функции в Си? Где находятся прототипы вариантов функции main()?

И разницы вобщем-то никакой - и то и то это всего лишь соглашение с используемой libc.

Ты просто нахально пользуешься отсутствие перегрузки функций в Си. И ты до сих пор не смог внятно объяснить зачем тебе так хочется именно unsigned int argc, что аж зудит.

Если других источников ориентации нет - то остаётся только так, да. Но это ж не всегда так.

Расскажи про свои источники ориентации на unsigned int argc.

Плевать.

Гораздо логичнее плевать на твои странные хотелки.

Тем более что оно не про Си.

А в чём принципиальная разница? В C++ эти типы ведут себя как-то иначе или компилируются в какой-то другой машинный код?

Хорошо, перефразирую - в «win32 native проге с стандартной ms библиотекой есть WinMain и нету main». А entry point не будет ни одно из них. Entry point - в статически слинкованной части rtl, он уже, среди прочего, вызывает одну из этих трёх обычных функций. Да, можно перенастроить линкер чтобы он сделал entry point’ом какую-то самописную функцию, но обычно так не делают. И argc argv ей точно никто не передаст, она должна будет сама их получать с помощью winapi.

Entry Point - это точка входа в код твоего приложения. Если ты написал виндовое приложение на Си, точкой входа может быть один из трёх вариантов, которые я перечислил выше. Какой код инициализации его вызывает никакого значения не имеет. В случае нативного консольного виндового приложения будет вызвана функция инициализации mainCRTStartup, которая вызовет main(). Есть и другие *CRTStartup функции инициализации, вызывающие другие точки входа в приложении на Си.

hummer
() автор топика
Последнее исправление: hummer (всего исправлений: 1)
Ответ на: комментарий от hummer

Твоё утверждение о том, что целочисленное переполнение unsigned менее болезненно, чем signed - просто враньё.

Повторяю в третий раз, я не раз видел баги, связанные именно с тем, что кто-то ткнул наобум int (видимо по тем самым гайдам для нубов) и не учёл signed переполнение, в то время как для unsigned там всё бы работало просто так, без спец. проверок.

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

Разумеется. Не надо делать мутный код. Надо использовать типы по назначению.

Статическую типизацию придумали как раз для выявления как можно большего числа подобных проблем на этапе компиляции

Если значение беззнаковое по логике работы кода - ставь беззнаковый тип. И проблем не будет.

отключаешь надоедливые предупреждения компилятора о несоответствии типов

Враньё, не отключаю. Например, signed vs unsigned comparsion всегда включаю - от него может быть много скрытых багов. И как раз благодаря ему понимаю всю глупость int argc.

Да что ты говоришь? Ты вообще знаешь, что такое прототип функции в Си? Где находятся прототипы вариантов функции main()?

Штатно не предусмотрены, она осталась почти нетронутой с тех времён, когда прототипы вообще были не нужны, а функции по сути были чуть расширенными метками.

Ты просто нахально пользуешься отсутствие перегрузки функций в Си.

Пользоваться отсутствием - странное выражение. Вот тебе аналогичная ситуация: колбек qsort()’а. У него в прототипе указаны аргументы типа void*, а на самом деле можно принять другой указатель и тайпкастить свой колбек в тип, нужный qsort()’у.

И ты до сих пор не смог внятно объяснить зачем тебе так хочется именно unsigned int argc, что аж зудит.

Зудит у тебя. А я уже всё объяснил и не раз.

Расскажи про свои источники ориентации на unsigned int argc.

См. выше.

Гораздо логичнее плевать на твои странные хотелки.

Так я тебя и не заставляю их учитывать.

А в чём принципиальная разница? В C++ эти типы ведут себя как-то иначе или компилируются в какой-то другой машинный код?

В C++ другие шаблоны программирования, более высокоуровневые. И учитывать детали представления чисел в железе там, возможно, и правда не всегда уместно. По той же причине что в Java.

Entry Point - это точка входа в код твоего приложения.

Ну, смотря что считать кодом приложения. Обычно статическую часть CRT, расположенную в том же .exe-файле, тоже туда относят. Ну да ладно, это не важно. Важнее другое.

mainCRTStartup, которая вызовет main()

Тут явно видно, что main() это не какая-то спецфункция с особенным режимом компиляции, а всего лишь обычная вызываемая функция. И, соответственно, можно изменить её прототип там, где её вызывают и там, где описано её тело, и всё должно работать, а компилятору до этого дела быть не должно.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Повторяю в третий раз, я не раз видел баги, связанные именно с тем, что кто-то ткнул наобум int (видимо по тем самым гайдам для нубов) и не учёл signed переполнение, в то время как для unsigned там всё бы работало просто так, без спец. проверок.

Не надо повторять, просто приведи пример.

Разумеется. Не надо делать мутный код. Надо использовать типы по назначению.

int argc используется вполне по назначению - целое число базового типа. Кстати, а почему ты не возмущаешься тем, что используется не short? Ведь реально там таких больших чисел не бывает.

Если значение беззнаковое по логике работы кода - ставь беззнаковый тип. И проблем не будет.

Ещё как будут, потому что позже ты захочешь произвести какую-то арифметику с другими переменными, часть из которых будут знаковые.

Враньё, не отключаю. Например, signed vs unsigned comparsion всегда включаю - от него может быть много скрытых багов. И как раз благодаря ему понимаю всю глупость int argc.

Какая красивая подмена тезиса. А ещё во вранье меня обвиняешь :-))

Штатно не предусмотрены, она осталась почти нетронутой с тех времён, когда прототипы вообще были не нужны, а функции по сути были чуть расширенными метками.

Оно не предусмотрено потому что main() вызывается совсем не твоим кодом и изменить его у тебя нет никакой стандартной возможности.

Пользоваться отсутствием - странное выражение.

Совсем не странное. Функции в Си вызываются только по имени, без проверки количества и типов параметров. Именно этим ты и пользуешься.

Вот тебе аналогичная ситуация: колбек qsort()’а. У него в прототипе указаны аргументы типа void*, а на самом деле можно принять другой указатель и тайпкастить свой колбек в тип, нужный qsort()’у.

Нет там никакого кастинга, там будет лишь warning от кодоанализатора на этапе компиляции. Ещё раз, в C нет перезагрузки функций. В отличии от C++ или Java ты не можешь создать две функции с одним именем, отличающиеся лишь числом и/или типами или порядками типов аргументов. Ты ожидаешь такого же поведения (с warning-ом) и для unsigned int argc в main() но там у тебя нет доступа к прототипу и вызывающий код не твой. Именно поэтому компилятор бьёт тебя по рукам от такой наглости.

Зудит у тебя. А я уже всё объяснил и не раз.

Меня просто забавляет твоя распальцовка. Ты ничего не объяснил. Ты лишь зачем-то сослася на то, что деление на два у unsigned int проще и переполнение иное. Вот реально чем тебе мешает signed int argc? Ты его всегда делишь на два или у тебя так много аргументов, что argc может переполниться?

Так я тебя и не заставляю их учитывать.

Ты и не можешь кого-то заставить, но ты как-то очень громко возмущаешься из-за ерунды.

В C++ другие шаблоны программирования, более высокоуровневые. И учитывать детали представления чисел в железе там, возможно, и правда не всегда уместно. По той же причине что в Java.

Даже в Java эти детали учитываются. Там даже есть беззнаковый оператор сдвига вправо. Другие шаблоны программирования в C++ тут совсем не причём, поэтому рекомендации Google о предпочтении signed типов вполне умустны и для C кода.

Тут явно видно, что main() это не какая-то спецфункция с особенным режимом компиляции, а всего лишь обычная вызываемая функция. И, соответственно, можно изменить её прототип там, где её вызывают и там, где описано её тело, и всё должно работать, а компилятору до этого дела быть не должно.

У компилятора нет доступа к коду, который вызывает main() и этот код не модифицируемый. Компилятор просто следует стандарту.

hummer
() автор топика
Ответ на: комментарий от hummer

Не надо повторять, просто приведи пример.

Увы, не запоминал. Но суть обычно сводится к тому, что переполнение из плюса в минус - намного больше выбивается из обычной логики работы, чем переполнение в ноль.

int argc используется вполне по назначению - целое число базового типа. Кстати, а почему ты не возмущаешься тем, что используется не short? Ведь реально там таких больших чисел не бывает.

Там не целое число, а неотрицательное целое. Потому что это размер массива. А вот принципиальных причин не иметь больше 65535 аргументов я не вижу.

Ещё как будут, потому что позже ты захочешь произвести какую-то арифметику с другими переменными, часть из которых будут знаковые.

Подскажу ещё: если вычесть друг из друга два беззнаковых числа, второе окажется больше первого, и ты забудешь, что результат такого вычитания положительный - проблемы тоже будут. Но, как я уже писал, надо просто знать, что такое беззнаковая арифметика и не путать её со знаковой. Знаковые переменные перед использованием можно сконвертировать в беззнаковые, проверив разумеется, что ничего не переполнилось при этом. Если же никаких проверок не делать, то проблемы будут и так и так. Единственный реально неприятный случай, который я могу вспомнить - это когда у тебя есть две переменные, одна знаковая, другая нет, при этом они разной разрядности и ты не знаешь, у какой разрядность больше (size_t vs off_t), и тебе надо использовать их в общей формуле.

Ещё пример, которыйты наверно считаешь аргументом в пользу signed:

if(a-b>2) { ... }

В случае unsigned тут будут очевидные проблемы, если a<b. В случае signed очевидных проблем не будет, радость да? Зато есть неочевидные: если a-b не влезает в диапазон signed int’а, оно всё равно переполнится и сделает тебе проблемы. Только для unsigned это всё словится на первом же тесте, а для signed имеет шанс проскочить в прод и проявиться там спустя несколько нет, когда уже некому фиксить баги. Правильно так:

if(a>b && (unsigned)(a-b)>2) { ... }

Разумеется, если переменные изначально unsigned то тайпкаст не нужен. Другие НЕправильные варианты, которые ты, возможно, захочешь использовать: if(a>b+2) и if(a-2>b) - все они так или иначе могут переполниться.

Какая красивая подмена тезиса.

Подмены нет. В main() не несоответствие типа, а полностью продуманная корректировка.

Оно не предусмотрено потому что main() вызывается совсем не твоим кодом и изменить его у тебя нет никакой стандартной возможности.

Есть, конечно. Написать свою libc - вполне себе стандартная возможность С-компилятора. Более того, почти все libc (из популярных - думаю вообще все) тем же самым копмилятором и компилируются.

Именно этим ты и пользуешься.

Хорошо, я пользуюсь тем, что Си не прячет от программиста возможность сделать вызов по любому адресу, вне зависимости от того, что по нему расположено. Всё даже «хуже»: в ряде случаев вызвать можно массив unsigned char’ов, в котором машинный (скомпилированный заранее) код функции.

Нет там никакого кастинга, там будет лишь warning от кодоанализатора на этапе компиляции

С main должно быть то же самое, в худшем случае. А вообще конечно следует unsigned argc вписать в официальные спецификации.

вызывающий код не твой. Именно поэтому компилятор бьёт тебя по рукам от такой наглости.

Компилятор не может знать, чей там вызывающий код. Может быть и мой. Библиотеку, повторюсь, может написать кто угодно. В любом случае, библиотека - не часть компилятора.

Вот реально чем тебе мешает signed int argc?

Уже писал выше, повторю: я хочу сделать цикл по аргументам, такой: for(i=1;i<argc;i++) { .... argv[i] .... }, и индекс для массива i, как и следует, объявил size_t. Из-за дурацкого signed argc такая конструкция пишет варнинги.

У компилятора нет доступа к коду, который вызывает main() и этот код не модифицируемый

Доступа и правда нет, а вот код ещё как модифицируемый.

Компилятор просто следует стандарту.

Пусть следует стандарту на компилятор (хотя и это спорно). А стандартом на библиотеку пусть занимается библиотека. Компилятор может её для этого предоставить спец. инструменты по прописыванию динамических прототипов в *.h. Решать, в любом случае, программисту.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ты используешь size_t в качестве типа индекса массива. Индекс массива в Си - это, строго говоря, не индекс, а смещение в адресной арифметике и использовать для него size_t не вполне корректно. Более корректно использовать intptr_t или uintptr_t, добавленные в C99. Как видишь и тут есть знаковый и беззнаковый варианты. Следующий код прекрасно компилируется clang-ом:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char **argv)
{
    for (intptr_t i = 0; i < argc; i++) {
        printf("%ld's argument is: %s\n", i, argv[i]);
    }

    return 0;
}

Видишь, тебе не надо переписывать libc (да ты и не собирался это делать, а лишь грозился).

size_t - это тип, возвращаемый оператором sizeof, то есть это не смещение, а размер, что не одно и то же. Смещение вполне может быть отрицательным. Например если ты бежишь по массиву инкрементом указателя и затем сравниваешь с предыдущим значением:

#include <stdio.h>
#include <stdbool.h>

bool is_sorted(char *s)
{
    while(*s++ && *s) {
        if (s[0] < s[-1]) {
            return false;
        }
    }

    return true;
}

int main()
{
    char *s1 = "abcdwz";
    char *s2 = "abcdzw";

    printf("%s ==> %d\n", s1, is_sorted(s1));
    printf("%s ==> %d\n", s2, is_sorted(s2));

    return 0;
}

В Java не просто так почти полностью отказались от unsigned типов. Слишком много от них проблем.

Ещё пример, которыйты наверно считаешь аргументом в пользу signed:

if(a-b>2) { ... }

В случае unsigned тут будут очевидные проблемы, если a<b. В случае signed очевидных проблем не будет, радость да? Зато есть неочевидные: если a-b не влезает в диапазон signed int’а, оно всё равно переполнится и сделает тебе проблемы. Только для unsigned это всё словится на первом же тесте, а для signed имеет шанс проскочить в прод и проявиться там спустя несколько нет, когда уже некому фиксить баги. Правильно так:

if(a>b && (unsigned)(a-b)>2) { ... }

Бороться с int overflow/underflow нужно совсем другими методами. Просто какие-то переменные a и b могут содержать любые числа, но когда ты пишешь программу ты должен понимать смысл данных и вовремя их валидировать.

Пусть следует стандарту на компилятор

Так он и следует своему стандарту: https://stackoverflow.com/questions/2108192/what-are-the-valid-signatures-for-cs-main-function

hummer
() автор топика
Ответ на: комментарий от hummer

Более корректно использовать intptr_t или uintptr_t, добавленные в C99.

Нет, не более. Максимальный размер объекта влезает в size_t.

Как видишь и тут есть знаковый и беззнаковый варианты.

Нужен - беззнаковый, потому что смещения назад от argv+0 быть не может. А знаковый и ssize_t есть.

Видишь, тебе не надо переписывать libc (да ты и не собирался это делать, а лишь грозился).

Разумеется не нужно, потому что нигде в libc не прописано требование писать signed int argc в коде пррограмм. Это исключительно дурь clang’а.

Смещение вполне может быть отрицательным

Конечно может, но не тут (смещение от начала массива, при том что нас интересует именно содержимое массива).

Например если ты бежишь по массиву инкрементом указателя и затем сравниваешь с предыдущим значением

Это «-1» незачем сравнивать с argc.

В Java не просто так почти полностью отказались от unsigned типов. Слишком много от них проблем.

На уровне скриптописателей - много. Опять посоветую им просто не писать на Си.

Бороться с int overflow/underflow нужно совсем другими методами. Просто какие-то переменные a и b могут содержать любые числа, но когда ты пишешь программу ты должен понимать смысл данных и вовремя их валидировать.

Ты совершенно не в теме того, что может требоваться от системного кода. Писать чисто прикладной код - иди в джаву, повторюсь, и не лезь с глупыми советами.

Так он и следует своему стандарт

Это стандарт на библиотеку, а не на компилятор. Просто в тех документах под названием C89 C99 и т.д. всё свалено в кучу. При этом стандарт на компилятор имеет смысл везде, хоть и дискуссионный (поэтому даже к нему у нормальных компиляторов подход гибкий, настраиваемый), а вот стандарт на библиотеку может вообще терять смысл на необычных платформах, и зависеть от него компилятор в общем случае вообще не должен.

firkax ★★★★★
()
Ответ на: комментарий от EXL

Кто-то видимо не знает историю того, почему в STL у C++ затесался size_t

В Обероне вообще беззнаковых типов нет и нет таких проблем.

X512 ★★★★★
()
Ответ на: комментарий от firkax

Нет, не более. Максимальный размер объекта влезает в size_t.

Но не все возможные значения смещения (индекса) массива.

Нужен - беззнаковый, потому что смещения назад от argv+0 быть не может. А знаковый и ssize_t есть.

Смещение назад от непервого элемента массива вполне может быть отрицательным. Упомянутый тобой знаковый ssize_t не является частью языка C и компилятор может его вообще не знать.

Разумеется не нужно, потому что нигде в libc не прописано требование писать signed int argc в коде пррограмм. Это исключительно дурь clang’а.

Это прописано в стандарте языка. Напиши в комитет стандартизации аргументированное предложение по изменению стандарта, а потом расскажи что тебе от туда ответили.

Это «-1» незачем сравнивать с argc.

Это -1 является вполне валидным значением, а ты ограничиваешься unsigned. Нет обязательного требования обращаться к членам массива лишь через указатель на начало. Указатель может инкрементироваться и относительно такого указателя можно обращаться к элементам до него. Строго говоря в C нет настоящих массивов, а есть адресная арифметика и некий синтаксический сахар, позволяющий писать такие вещи, как a[3], 3[a], b[-1].

На уровне скриптописателей - много. Опять посоветую им просто не писать на Си.

Для начала тебе нужно перестать путать Java со скриптовыми языками. Иначе у тебя просто недостаточно компетенции для таких советов.

Ты совершенно не в теме того, что может требоваться от системного кода. Писать чисто прикладной код - иди в джаву, повторюсь, и не лезь с глупыми советами.

Ты совершенно не в состоянии аргументировать свои глупые заявления.

Это стандарт на библиотеку, а не на компилятор. Просто в тех документах под названием C89 C99 и т.д. всё свалено в кучу.

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

hummer
() автор топика
Ответ на: комментарий от hummer

Ну если только извратиться с символьным типом. В последующие версии Оберона завезли CHAR для UTF-16. Для UTF-32 нету.

X512 ★★★★★
()
Ответ на: комментарий от X512

Ну значит практически то же самое, как в Java. А особо упёртые сишники до сих пор ломают копья о небесную твердь.

hummer
() автор топика
Ответ на: комментарий от hummer

Java делалась по образцу Оберона, только в Java виртуальная машина и байткод, а Оберон компилируемый в нативный код.

X512 ★★★★★
()
Ответ на: комментарий от hummer

Но не все возможные значения смещения (индекса) массива.

Все возможные (валидные с точки зрения размещённых там без хаков объектов) значения смещения массива от его начала влезают в size_t. Потому что смещение от начала не может быть меньше нуля и не может быть больше или равно длине.

Смещение назад от непервого элемента массива вполне может быть отрицательным. Упомянутый тобой знаковый ssize_t не является частью языка C и компилятор может его вообще не знать.

Хватит приводить аргументы к выдуманным тобой ситуациям. Речь не шла про смещение назад от середины, речь шла про индекс от начала argv. Придумай ситуацию, где смещение назад придётся сравнивать с argc, и объясни, как знаковость argc что-то улучшит - тогда поговорим на эту тему. Свой пример о том, как знаковость вредит - я уже привёл.

Это прописано в стандарте языка.

Повторюсь, это стандарт на библиотеку. При этом в библиотеке он по факту не принуждается, потому что компилятор не даёт для этого инструментов. Отсюда следствие - переделывать библиотеку не нужно. В стандарте на компилятор ничего про это не может быть сказано.

Напиши в комитет стандартизации аргументированное предложение

Зачем? Комитет не имеет никаких директивных полномочий. 32 года назад они провели полезную работу по систематизации и обобщению фактической логики работы компиляторов и системных библиотек актуальных на то время систем, получившийся приведённый к единой системе обзор опубликовали как «С89». После этого они занимаются только занятием спорной полезности - изданием раз в 10 лет мимикрирующих под нормативные документов с рекомендациями для авторов компиляторов вперемежку (ещё бы отличить, где что) с продолжением подведения итогов фактического их (компиляторов и библиотек) развития.

Нет обязательного требования обращаться к членам массива лишь через указатель на начало

И что? Повторяю в десятый раз, речь идёт про переменную, которая хранит длину этого массива, и используется для сравнения с индексом от начала массива. Она однозначно не может быть отрицательной. В каких-то других местах, разумеется, отрицательные числа могут быть, только это другая тема.

Строго говоря в C нет настоящих массивов, а есть адресная арифметика и некий синтаксический сахар

Зачем умничаешь? Дай теперь определение настоящего массива, иначе твоя фраза бессмысленна. Могу сумничать в ответ: в си и функций настоящих нет, а есть только синтаксический сахар для операции «запушить значения по списку в стек/регистры и перейти по адресу с сохранением адреса возврата». А разгадка проста: Си - не скриптовый язык для оперирования сущностями, а инструмент для упрощения написания и окроссплатформливания машинного кода, по сравнению с ассемблером.

Для начала тебе нужно перестать путать Java со скриптовыми языками

По сравнению с Си это скриптовый язык. По сравнению с PHP - нет. Но у нас первый случай.

firkax ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.