LINUX.ORG.RU

Как перейти с новомодных недоязычков на православные C/C++?

 , ,


0

5

Честно, меня не беспокоит отсутствие вменяемых инструментов работы с юникодом. Меня в C и C++ отталкивают две вещи.

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

Вторая - заголовочные файлы. Как-то раз, давно, я писал простенькое приложение. Я создал заголовочный файл, в котором хранились глобальные (для всего приложения) значения. Подключаю его в нескольких .cpp файлах - линкер ругается, не может он что-то там слинковать. Добавляю в заголовочник #pragma once - компилятор ругается, что у многих .cpp нет к нему доступа. Бомбанул, перестал писать. Конечно, жопы прожжёных сишников и крестовиков и не такое видали, но я не выдержал.

При чём тут новомодные недоязычки? В них такого нет. Их компиляторы умеют разруливать такие вещи. Понятно, что C создавался ещё тогда, когда компьютеры могли только по одному файлу построчно читать код, и все эти видимости функций были оправданы. Но уже в конце 90х и начале 00х были огромные проекты. Операционные системы, браузеры, игры. Памяти в компьютерах уже должно было хватить на то, чтобы обрабатывать огромные объёмы информации. Да даже сейчас есть огромные жирные проекты (привет, Chrome), которые написаны на C++ и требуют по 16 гигов оперативки для сборки. Неужели наличие таких «особенностей» - преимущество перед другими языками?

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

Как перейти с новомодных языков на C/C++ и перестать бомбить с описанных в посте проблем?


Да, я знаю, что C и C++ - очень разные языки. Но всё же это некая основа программирования во всём мире, поэтому я упомянул их вместе.



Последнее исправление: Original_1 (всего исправлений: 2)

Как перейти с новомодных языков на C/C++ и перестать бомбить с описанных в посте проблем?

Проникнуться красотой того, что открыв заголовочный файл, ты можешь читать интерфейс «модуля» без мусора деталей реализации.

Подключаю его в нескольких .cpp файлах - линкер ругается, не может он что-то там слинковать. Добавляю в заголовочник #pragma once - компилятор ругается.

Пару раз разрулишь, и привыкнешь. Ничего страшного.

При чём тут новомодные недоязычки? В них такого нет

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

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

Проникнуться красотой того, что открыв заголовочный файл, ты можешь читать интерфейс «модуля» без мусора деталей реализации.

откройте себе новомодные header-only библиотеки… ;-) заодно можно скоротать вечерок-другой их компелянием

MKuznetsov ★★★★★
()

Меня в C и C++ отталкивают две вещи.

Только две? А что привлекает?

Но уже в конце 90х и начале 00х были огромные проекты. Операционные системы, браузеры, игры. 

Узбагойзя, операционные системы больше не будут :) игры тоже давно не требуют написать половину ОС защищенного режима с плоской моделью памяти и своими драйверами.

Как перейти с новомодных языков на C/C++ и перестать бомбить с описанных в посте проблем?

Это еще не проблемы :) просто не бомби.

slackwarrior ★★★★★
()

Это вброс такой? Прототипы - не проблема. Суть в том, что ты должен построить нечто, что даст возможность компилятору проверять правильность написанного далее кода. Прототип одна из таких фишек. Ты можешь просто описать что у тебя есть, а как это реализовано - не важно. К тому же, не весь код можно скомпилировать не зная заранее прототипов. То есть код вызова должен разный получиться в зависимости от того, что написанно в этом прототипе.

zerhud
()

как.. перестать бомбить

Понять зачем так сделано и какие преимущества это даёт.

zerhud
()
Ответ на: комментарий от slackwarrior

Узбагойзя, операционные системы больше не будут :) игры тоже давно не требуют написать половину ОС защищенного режима с плоской моделью памяти и своими драйверами.

Поправил пост, добавил контекст.

Памяти в компьютерах уже должно было хватить на то, чтобы обрабатывать огромные объёмы информации. Да даже сейчас есть огромные жирные проекты (привет, Chrome), которые написаны на C++ и требуют по 16 гигов оперативки для сборки.

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

Ну как тебе сказать... удешевление памяти, приведшее к, скорее хорошо, а то бы ты бомбил как сложно оптимизировать софт под 16 Mb RAM

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)

Добавляю в заголовочник #pragma once - компилятор ругается, что у многих .cpp нет к нему доступа

покажи, как воспроизвести такую ошибку.

При чём тут новомодные недоязычки? В них такого нет. Их компиляторы умеют разруливать такие вещи

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

Как же они тогда взаимодействуют с окружением? А все очень просто: они линкуются с кодом на сишке, который делает за них всю грязную работу.

Что до модулей C++, то они нафиг не нужны.

Lrrr ★★★★★
()
Ответ на: комментарий от quantum-troll

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

Original_1
() автор топика

Нужно просто осознать зачем так сделано.

Это фича, а не потому что «C создавался ещё тогда, когда компьютеры могли только по одному файлу построчно читать код».

Описание прототипов функций отдельно от имплементации - это вообще отличная вещь которой не хватает в новомодных языках. Из-за чего нормально писать на этих языках можно только если используешь IDE, которые показывают список функций в панельке слева. Но если ты захочешь подсмотреть что-то, например, на github не скачивая, то это превращается в ад. Плюс панельки не показывают некоторую полезную инфу, как, например, комментарии, которые могу прилагаться, или группировки. А иногда из-за такого интерпретатор/компилятор перестаёт поддерживать некоторые сценарии, как, например, в Python нельзя в методе класса указать что тип возвращаемого значения это тип экземпляра этого класса (self).

Ну, и это ты можешь делать либо в файле с имплементацией, либо отдельно заголовочным файлом - как тебе удобно.

Выносить с самого начала в заголовочные файлы я бы не рекомендовал. Это нужно делать когда уже есть рабочий MVP для публикации. Ну, разве что ты делаешь совсем правильно: дизайн и только потом имплементация, но ИМХО такой подход работает только в теории.

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

Нет, я не против появления новых языков. Я за прогресс и развитие. Я положительно отношусь к С++, к Python (для определённого круга задач), с надеждой наблюдаю за Rust. Просто многие из новых языков пытаются изначально отказываться от «сложностей языка С», позиционируют это как фичу, а в результате привносят еще больше сложностей.

Kroz ★★★★★
()
Ответ на: комментарий от quantum-troll

Вопрос: зачем? Даже C++ не может вытерпеть сам себя и начинает разваливаться на cppfront, carbon и прочие попытки спастись от легаси.

затем что люди не осилили Сpp. У которого две сути - строить и обобщать абстракции и в наобобщённом «херачить код блджаЪ» :-)

Всегда есть а-ля «си-с-классами-и-stl» и нахлобучка которая предоставляет эти шаблоны и классы (DSL). И то и другое надо уметь, оба требуют принципиально разной квалификации. C++ предоставляет средства для обоих случаев.

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

С - это взрослый язык, в котором решены многие проблемы, с которыми сталкиваются при написании серьезных приложений.

Но большинство всё ещё использует ANSI C, а многие ещё и с гнутыми расширениями.

Описание прототипов функций отдельно от имплементации - это вообще отличная вещь которой не хватает в новомодных языках.

Почему бы их не сделать опциональными?

Original_1
() автор топика

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

Это нормально. Решается грамотным проектированием. Всё, что наружу — выносится в заголовочный файл.

Вторая - заголовочные файлы.

Плохи не сами заголовочные файлы. Сами они (как и вообще концепция препроцессора) — очень мощное средство. Плохо то, что заголовочные файлы используются в C и C++ вместо отсутствующих там модулей. В то время как в презираемом недавними школьниками объектном Паскале нормальные модули есть уже 30 лет.

Я создал заголовочный файл, в котором хранились глобальные (для всего приложения) значения. Подключаю его в нескольких .cpp файлах - линкер ругается, не может он что-то там слинковать.

Я не люблю ванг и не люблю ванговать. Но сейчас рискну: вероятно, ты вынес туда не константы и не объявления переменных, а сами переменные. Препроцессор размножил одно глобальное имя на несколько .cpp и при попытке компоновки у линкера бомбануло.

Если я угадал, это решается просто. Если тебе эти переменные ДЕЙСТВИТЕЛЬНО нужны в качестве глобальных, создаёшь два файла: globals.h и globals.cpp. В первом пишешь:

extern int someCounter;
extern double someSum;

Во втором:

int someCounter;
double someSum;

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

У отсутствия модулей есть и другие минусы. Но в C++20 модули наконец-то появились, может быть, они всё же придут окончательно. А пока просто аккуратнее пиши заголовочники и не забывай про стражи компиляции (современные IDE расставляют их автоматически).

Меня в C++ больше расстраивает отсутствие стандартной сборочной системы, из-за чего люди тащат в свои проекты разнокалиберный хтонический ужас: кто cmake, кто автотулзы… На мой взгляд, нужен стандартный декларативный формат файла проекта со строгим синтаксисом. Ошибся в синтаксисе — получил по рукам сразу. А для случаев, когда надо сделать что-то нестандартное, предусмотреть какую-нибудь секцию custom или unsafe :)

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

Почему бы их не сделать опциональными?

прототипы функций и так опциональны

void callme(void){
...
}

int main(){
    callme();
    return 0;
}
olelookoe ★★★
()

Надо прочитать книжку для начинающих. Там эти вопросы должны разбираться.

vbr ★★★★
()

решается модулями

а чем это таким эти ваши модули намазаны, что на них слетаются как мухи?

статические библиотеки чем не устраивают?

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

Если тебе эти переменные ДЕЙСТВИТЕЛЬНО нужны в качестве глобальных

Например, у меня из файла загружается конфиг (TOML) и его значения присваиваются переменным.

создаёшь два файла

globals.h:

extern int testVarInt;

globals.c:

#include "globals.h" 

int testVarInt = 10;

main.c:

#include <stdio.h>

#include "globals.h"

int main(int argc, char* argv[])
{
    printf("%d\n", testVarInt);
    return 0;
}

gcc main.c:

/usr/bin/ld: /tmp/ccQJOM4D.o: в функции «main»:
main.c:(.text+0x11): неопределённая ссылка на «testVarInt»
collect2: ошибка: выполнение ld завершилось с кодом возврата 1

main.c:

#include <stdio.h>

#include "globals.h"

int testVarInt;

int main(int argc, char* argv[])
{
    printf("%d\n", testVarInt);
    return 0;
}

a.out:

0

/usr/bin/ld -v:

GNU ld version 2.37-36.fc36
Original_1
() автор топика
Ответ на: комментарий от Original_1

Хм, а как собираешь? Может, у тебя globals.c отсутствует в файле проекта/Makefile? Его, если что, надо скомпилировать, как и main.c.

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

Мой косяк. Надо было gcc main.c globals.c globals.h. Ну и я ещё нагуглил генератор мейкфайлов, с ним тоже работает. Спасибо за объяснение.

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

Но большинство всё ещё использует ANSI C, а многие ещё и с гнутыми расширениями.

С продолжает развиваться. Как минимум С17 уже есть. С часто используют в ембедед, т.к. либы поменьше плюсовых, а ресурсы ограничены. И да - С и С++ всё-таки разные языки, хотя синтаксис и похож.

Juan-Carlos
()
Ответ на: комментарий от Juan-Carlos

С и С++ всё-таки разные языки

Но они как бы основные, поэтому упомянул вместе.

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

Первая - прототипы функций.

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

Вторая - заголовочные файлы.

В си есть модули, не те модули что сейчас везде модули, а нормальные изолированные единицы компиляции. Объявляй глобальные переменные в той компилируемой единице где она нужна, если тебе нужна переменная доступная из множества компилируемых единиц то ты можешь написать функцию для обращения к этой переменной, если для тебя это лишние вызовы функций то ты всегда можешь засунуть переменную куда угодно и написать что она extern. Заголовочные файлы это для препроцессора они просто приклеиваться к тому файлу который ты пишешь исходному, это просто сокращение записи всех кишков одной строчкой.

Прототипы функций/данных вместе с заголовочными файлами это красота. Последнее чисто для cpp как автоматизация предобработки исходного кода, я бы ещё помимо c pre processor добавил c post processor. Например для замены символьных идентификаторов для поиска в хеш табличках на числовые да и вообще кучу всего можно там постпроцессорить.

Допустим в си ненужны были бы прототипы функций и не было заголовочных файлов. Тыб помер пока искал бы в исходниках описание структуры или хотел бы посмотреть какие типы у аргументов функции.

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Тыб помер пока искал бы в исходниках описание структуры

А что, grep или Ctrl+F (или аналог у вимеров) уже нельзя использовать?

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

Да можно использовать всё что есть. Только вот проблемка придётся для этого иметь все исходные тексты программы. И так вместо пары сотен байт поиск будет вестись в гораздо больших объёмах. Это будет жопа если у тебя проект с зависимостями. Да банально glibc и понеслась, для хелоуворда придётся иметь все исходники всего от чего он зависит.

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от Original_1

где ты там прототип-то нашел?

с прототипом

void callme(void);

int main(){
    callme();
    return 0;
}

void callme(void){
// some code here
}

без

void callme(void){
// some code here
}

int main(){
    callme();
    return 0;
}

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

в крестах, которые ты тут упоминал, примерно так все и работает. все члены класса доступны членам класса изнутри класса.

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

То есть для тебя это фундаментальная проблема? Фатальный недостаток и т.д? =)

dron@gnu:~$ gcc ggg.c -Wno-implicit-function-declaration
dron@gnu:~$ ./a.out 
25
#include <stdio.h>

int main()
{
    printf("%d\n",foo(5));
    return 0;
}

int foo(int x)
{
   return x*x;
}

Но не надо так.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)

Никак. Если это для Вас проблемы, то никак. Лучше создавать на лоре темы в стиле «как мне в питоне скопировать два байта из стека в кучу» и даже не тратить силы на изучение С/С++.

С/С++ ужастные ЯП, это надо просто накрепко запомнить и не касаться их даже шестифутовой палкой.

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 2)

Сишка нифига не православное. Православное - это когда динамической памяти нет ваще. Чтобы запросить у операционки память одним куском и разметить её на этапе конпеляции. Есть такое?

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

например, в Python нельзя в методе класса указать что тип возвращаемого значения это тип экземпляра этого класса (self).

Как это нельзя? Можно указать его в кавычках, можно использовать from __future__ import annotations, в 3.11 можно будет использовать typing.Self.

А если по теме сообщения, то если код на Python хорошо написан, то он обычно понятен, тем более, что сейчас есть typing.Protocol, например. Если плохо написан, то тут не помогло бы даже если бы в нем были заголовки, как в C++.

В общем, свойство понятности, это чаще свойство разработчика, пишущего код, а не языка. Если речь не о bash, Perl или какой-нибудь экзотике.

emorozov
()
Ответ на: комментарий от DumLemming

ну и не используй malloc и free, проблема-то в чем? int memory_block[1024] = {0};

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

Православное - это когда динамической памяти нет ваще. Чтобы запросить у операционки память одним куском и разметить её на этапе конпеляции. Есть такое?

В С++ всем можно пользоваться без динамической памяти.

PMR аллокаторы встроены в стандартную библиотеку.

Пример https://godbolt.org/z/EnMYofK5P взят из этого видео https://www.youtube.com/watch?v=Zt0q3OEeuB0

В Zig тоже хорошая и явная работа с аллокаторами и памятью.

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

С/С++ ужастные ЯП, это надо просто накрепко запомнить и не касаться их даже шестифутовой палкой.

Может быть, но тут уж что есть. Я вот тут в Rust полез по поводу buttplug.io

Заходит прям очень тяжело. Вся эта идеология по владению и жизни объектов отдаёт какой-то лютой наркоманией относительно той же RAII в C++.

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

Зато в питоне нет таких проблем:-)

Если чо, пред. мой комментарий был частично саркастичным. Под разные задачи разные ЯП, если ТС не асиливает препроцессор и прототипы функций - наверное задачи под котопые делались С/С++ не его.

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

AntonI ★★★★★
()

Честно, меня не беспокоит отсутствие вменяемых инструментов работы с юникодом.

С первого предложения детектится наброс.

ox55ff ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Допустим в си ненужны были бы прототипы функций и не было заголовочных файлов. Тыб помер пока искал бы в исходниках описание структуры или хотел бы посмотреть какие типы у аргументов функции.

Зато бывает весело разбираться с вложенными макросами, особенно если они раскиданы по разным файлам.

BadUser
()
Ответ на: комментарий от Original_1

С - это взрослый язык, в котором решены многие проблемы, с которыми сталкиваются при написании серьезных приложений.

Но большинство всё ещё использует ANSI C, а многие ещё и с гнутыми расширениями.

И?

Получается что ANSI C достаточно взрослый язык.

Описание прототипов функций отдельно от имплементации - это вообще отличная вещь которой не хватает в новомодных языках.

Почему бы их не сделать опциональными?

Они и так опциональные.

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

Проникнуться красотой того, что открыв заголовочный файл, ты можешь читать интерфейс «модуля» без мусора деталей реализации.

Рассмешил так рассмешил! Лапша препроцессора, шаблонный мусор, каша из private/public. Обалденный интерфейс, всем рекомендую!

filosofia
()

ТС толстый тролль, лжец и девственник. Пытаться серьезно отвечать в его теме или на его комментарий — рак.

filosofia
()
Ответ на: комментарий от her_s_gory

Проникнуться красотой того, что открыв заголовочный файл, ты можешь читать интерфейс «модуля» без мусора деталей реализации.

Особенно если это шаблоны в C++.

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

На мой взгляд, нужен стандартный декларативный формат файла проекта со строгим синтаксисом.

Уже есть Meson.

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