Уведомления

Группа в Telegram: @pythonsu

#1 Май 3, 2017 08:57:24

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10008
Репутация: +  857  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

Shaman
C С приходится знать не про язык, а про операционку и предметную область.
Если не будешь знать язык, то будешь делать ошибки, даже полностью зная операционную систему и предметную область. Работать оно будет не так, как ты ожидаешь. Очень распространённая ошибка - вычисление размера указателя через sizeof вместо размера массива, прицепленного к этому указателю, - это от чего, от незнания операционной системы или предметной области? Нет же, просто человек не держит в голове семантику этой операции, поэтому ему кажется, что она сама там что-то сообразит. А многие не знают даже, что это именно операция одноместная, а не функция. В чём разница - функции можно передавать куда-то, тогда как операции передавать нельзя и они подчиняются правилам приоритета. Вообще, в C аппарат операций и их приоритетов очень мощный, за счёт этого код очень сильно сокращается, если сравнивать с аналогичным кодом на Паскале (Дельфи). А чтобы пользоваться этим мощным аппаратом, нужно знать стандарт. В общем, пиши на C практически; когда 100500 ошибок вылезет в самых неожиданных местах, когда ты посидишь в gdb несколько часов, чтобы понять хотя бы, в чём там дело, тогда ты и поймёшь силу стандарта. Как надоест запускать gdb всё время на каждый чих, так сразу стандарт и выучишь.



Отредактировано py.user.next (Май 3, 2017 08:59:10)

Офлайн

#2 Май 3, 2017 10:26:06

Shaman
Зарегистрирован: 2013-03-15
Сообщения: 1369
Репутация: +  88  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

py.user.next
Очень распространённая ошибка - вычисление размера указателя через sizeof вместо размера массива, прицепленного к этому указателю
Это детская ошибка, конечно же она от незнания языка и вызывает только умилительную улыбку. В том же C++ гораздо менее очевидных тонкостей на порядки больше.

Офлайн

#3 Май 3, 2017 10:55:42

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10008
Репутация: +  857  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

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

Shaman
В том же C++ гораздо менее очевидных тонкостей на порядки больше.
Там всё хуже, потому что сам язык хуже. То есть он должен был быть лучше, по идее, но получилось только хуже всё. Если брать аппарат операций, то в сишнике он понятный и простой и при этом мощный. В C++ же его стали менять и превратили в итоге в кашу-малашу - то есть ты его уже учить заманаешься, потому что он нелогичный какой-то. Или вот я всегда привожу в пример встроенные типы составные (список, очередь и подобные), ими никогда нельзя пользоваться сходу (как в питоне, например), их надо обязательно дописывать. В итоге, они как бы есть, но их как бы и нет. В питоне-то у тебя всё есть, в сишнике надо всё писать, а тут ни то ни сё. Да, и стандарт ты никогда весь не прочитаешь, потому что он большой, часто меняется, и там много лишнего, вообще в языке много лишнего. Сегодня что-то вводят, через год это же отменяют нафиг. Потом они ещё само ядро языка меняют, добавляя дубликаты конструкций. Вот поэтому сам питон классический на C сделан, а не на C++. В C меньше заморочек, учится он быстрее в несколько раз, и он не меняется каждый день.

По ядру языка Go не плох, но он плох в другом. То есть ядро языка, вообще, хорошо сделано. Например, когда все три сишных цикла for, while и do…while сведены к одному циклу for. Или там умный switch, у которого умные case'ы, в них там можно функции вызывать, да ещё эти функции могут быть анонимными. Но вот то, что мне для маленькой программки нужно тратить полтора мегабайта, ни с того ни с сего причём, или что там нет нормальной модели ООП, как в питоне, где можно нормально наследоваться, ничего не выдумывая, это его, конечно, полностью нивелирует. Просто коммерческий проект, какие-то вещи продуманы отлично, какие-то вещи не продуманы вообще (или просто не проделаны из-за какой-то гонки внутри компании). Мне вот надо программу сделать, она будет не больше 100Kb, да меньше даже, так вот на Go я её сделать не могу, потому что она получится 10Mb. Я вот хочу, допустим, пакет программ сделать небольших, я на C спокойно его сделаю, а на Go он займёт там полдиска (образно выражаясь), просто так, тогда как на C он займёт 100Kb, потому что все программы маленькие.

Вот программы 125Kb 53Kb 151Kb 76Kb 556Kb
[guest@localhost ~]$ ll /bin/ls
-rwxr-xr-x. 1 root root 125372 авг 15 2013 /bin/ls
[guest@localhost ~]$ ll /bin/cat
-rwxr-xr-x. 1 root root 53316 авг 15 2013 /bin/cat
[guest@localhost ~]$ ll /bin/grep
-rwxr-xr-x. 1 root root 151120 окт 29 2013 /bin/grep
[guest@localhost ~]$ ll /bin/sed
-rwxr-xr-x. 1 root root 76384 авг 5 2013 /bin/sed
[guest@localhost ~]$ ll /bin/gawk
-rwxr-xr-x. 1 root root 556588 авг 4 2013 /bin/gawk
[guest@localhost ~]$
Вот они все вместе весят в пределах мегабайта, причём ими можно дофига чего сделать. А в Go то же самое будет весить 100Mb просто так, по желанию авторов, потому что они там что-то считают.

Так что из этих трёх языков - C, C++, Go - C лучше всего подходит для быстрой, экономной и надёжной разработки.



Отредактировано py.user.next (Май 3, 2017 11:24:23)

Офлайн

#4 Май 3, 2017 12:24:22

Shaman
Зарегистрирован: 2013-03-15
Сообщения: 1369
Репутация: +  88  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

Мне D понравился, как практичный и минимально шокирующий привыкшего к ООП прога. Выраженных проблем с распуханием не имеет, миксуется с C/C++/Python и при необходимости собирается в динамически линкуемый бинарник.

Офлайн

#5 Май 4, 2017 00:08:58

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10008
Репутация: +  857  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

Shaman
Мне D понравился, как практичный и минимально шокирующий привыкшего к ООП прога.
Ну, синтаксис я смотрел, для меня он всё равно что C++. Просто как C++ только с другим синтаксисом. Так что я его даже не рассматривал для изучения. C++ вот мне нужен для написания на Qt графического интерфейса. Было бы там на C возможно делать, я бы на C писал его. Всё равно, даже если на C++ пишу что-то, то это получается код на C только с дополнительными возможностями вроде классов, шаблонов для функий (чтобы произвольные типы принимала). Но питон в этом плане удобнее, у него как бы UX выше, чем у C++. На нём потому быстрее и пишешь, что в нём всё удобнее сделано. А в C++ долго нужно описывать, конструктор, деструктор, пространства имён обязательно проставлять (кстати, из-за них код удлинняется, больше букв становится, читать длиннющий код скучно). Не люблю читать цппшный код только потому, что там слишком много букв всегда. Какая-нибудь маленькая программка, а читаешь её целый час. Вот этого нет в C, потому что в коде только самое нужное записано.



Офлайн

#6 Май 4, 2017 07:44:54

Shaman
Зарегистрирован: 2013-03-15
Сообщения: 1369
Репутация: +  88  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

py.user.next
Ну, синтаксис я смотрел, для меня он всё равно что C++. Просто как C++ только с другим синтаксисом.
Там семантика своя. Вот напишешь
int[3][4] arr;
arr[2][3] = 1;
и обломаешься с выходом за границы массива.
Некоторые концепции ближе к шарпу, вроде уборки мусора, проверки границ, разделения структур и классов, интерфейсов, делегатов и т.п. Своя мощная система шаблонов от которой нет ряби в глазах, более цельная система типов, встроенные динамические массивы, словари, диапазоны, срезы, поддержка контрактов, юниттестов, изолированность памяти потоков и ещё много всякого разного. Компилятор даже иногда предупреждает: “вот это не нужно писать как в C++, а то запутаешься”.
Некоторые фичи, появившиеся в последних стандартах плюсов, в D были гораздо раньше.

Отредактировано Shaman (Май 4, 2017 09:30:11)

Офлайн

#7 Май 4, 2017 10:50:51

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10008
Репутация: +  857  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

Shaman
Вот напишешь
int[3][4] arr;
arr[2][3] = 1;
и обломаешься с выходом за границы массива.
Что-то почитал, вроде перепутал индексы ты, есть проверка границ, но обращение к элементам обычное.
http://dlang.org/spec/arrays.html

Shaman
Некоторые концепции ближе к шарпу
Делегаты в шарпе, но в шарпе указателей на функции нет. То есть в C аналог делегатов делается через указатели на функции.

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

Это вот пример из проги своей
test_cmdline.c
#include <stdio.h>
#include <stdarg.h>
#include "CUnit/Basic.h"
#include "../cmdline.h"

void test_parse_argv_info(void);
void test_parse_argv_gender(void);
void test_parse_argv_words(void);
void test_progname_values(void);
void test_prog(void);
void test_opt(void);

int main(void)
{
CU_pSuite suite1, suite2;

suite1 = suite2 = NULL;

if (CU_initialize_registry() != CUE_SUCCESS)
return CU_get_error();

suite1 = CU_add_suite("suite for parse_argv", NULL, NULL);
if (suite1 == NULL) {
CU_cleanup_registry();
return CU_get_error();
}

suite2 = CU_add_suite("suite for other", NULL, NULL);
if (suite2 == NULL) {
CU_cleanup_registry();
return CU_get_error();
}

if (CU_add_test(suite1, "test info for parse_argv()",
test_parse_argv_info) == NULL
|| CU_add_test(suite1, "test gender for parse_argv()",
test_parse_argv_gender) == NULL
|| CU_add_test(suite1, "test words for parse_argv()",
test_parse_argv_words) == NULL) {
CU_cleanup_registry();
return CU_get_error();
}

if (CU_add_test(suite2, "test values for progname()",
test_progname_values) == NULL
|| CU_add_test(suite2, "test values for prog",
test_prog) == NULL
|| CU_add_test(suite2, "test values for opt",
test_opt) == NULL) {
CU_cleanup_registry();
return CU_get_error();
}

CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();

CU_cleanup_registry();
return CU_get_error();
}

char **make_argv(char *argv[], ...)
{
va_list args;
char **p = argv;

va_start(args, argv);
while ((*p++ = va_arg(args, char *)))
;
va_end(args);
return argv;
}

void test_parse_argv_info(void)
{
char *argv[10];

CU_ASSERT_FALSE(parse_argv(
1, make_argv(argv, "./prog", NULL)));
CU_ASSERT_FALSE(parse_argv(
2, make_argv(argv, "./prog", "--help", NULL)));
CU_ASSERT_FALSE(parse_argv(
2, make_argv(argv, "./prog", "--version", NULL)));
}

...

void test_progname_values(void)
{
char *progname(const char *);

CU_ASSERT_STRING_EQUAL(progname(""), "");
CU_ASSERT_STRING_EQUAL(progname("./"), "");
CU_ASSERT_STRING_EQUAL(progname("./prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("/dir/prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("/dir/dir/prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("./dir/prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("../dir/prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("../../dir/prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("../dir/../prog"), "prog");
CU_ASSERT_STRING_EQUAL(progname("..../prog"), "prog");
}

...

Shaman
и ещё много всякого разного
Есть такое поверье, что в C невозможно ничего написать, так как в нём ничего нет, и нужно из-за этого переходить на C++, но на деле оказывается, что на нём можно всё написать. ООП там реализуется через функции + структуры. Пока этот принцип не поймёшь, конечно будет казаться, что всё сложно. Однако если мыслишь исполнителями (представляешь программу в виде дерева исполнителей, управляющих исполнителями), то там всё просто становится. Нечасто, конечно, такое можно встретить, часто читаю код, там этого, как правило, нет. Недавно читал код Ассанджа (который в посольстве сидит), он написал несколько прог в 90-х, и вот читаешь его и там такая каша, хотя можно было сделать красиво. Всё-таки, если каша, то большую прогу не напишешь, запутаешься, надо структурировать, налаживать связь между частями, а для этого технологию надо знать. Многие не знают, вот и говорят, что нереально что-то большое на C писать.



Отредактировано py.user.next (Май 4, 2017 11:09:16)

Офлайн

#8 Май 4, 2017 13:05:11

Shaman
Зарегистрирован: 2013-03-15
Сообщения: 1369
Репутация: +  88  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

py.user.next
Что-то почитал, вроде перепутал индексы ты, есть проверка границ, но обращение к элементам обычное.
Проверяем.
C:
#include <stdio.h>

union {
int td[3][4];
int sd[12];
} tdata = {0};

int main()
{
tdata.td[1][0] = 1;
printf("%i , %i\n", tdata.sd[3], tdata.sd[4]);
return 0;
}
Выдаёт
0 , 1

D:
module main;

import std.stdio;

union TUnion {
int[3][4] td;
int[12] sd;
};

TUnion tdata;

int main()
{
tdata.td[1][0] = 1;
writefln("%s , %s", tdata.sd[3], tdata.sd[4]);
return 0;
}
Выдаёт
1 , 0

А если попробовать по-старинке
union TUnion {
int td[4][3];
int sd[12];
};
компилятор поругает:
ldc2  -w -g    -I/usr/import -c hello.d -of=obj/Debug/hello.o
hello.d(6): Warning: instead of C-style syntax, use D-style syntax 'int[3][4] td'
hello.d(7): Warning: instead of C-style syntax, use D-style syntax 'int[12] sd'

Отредактировано Shaman (Май 4, 2017 13:06:13)

Офлайн

#9 Май 4, 2017 13:38:13

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10008
Репутация: +  857  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

Shaman
компилятор поругает:
Так он же пишет не про границы массива, а про синтаксис. Ты там написал про выход за границы массива, я стал искать и его не увидел. Про синтаксис-то понятно, он поддерживает оба синтаксиса, но старается пересадить на чисто свой (из-за того, что в новом синтаксисе тип становится яснее, так как всё в одном месте записано).

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



Отредактировано py.user.next (Май 4, 2017 13:46:32)

Офлайн

#10 Май 4, 2017 14:33:36

Shaman
Зарегистрирован: 2013-03-15
Сообщения: 1369
Репутация: +  88  -
Профиль   Отправить e-mail  

Прошу помощи. Супер сложное задание!

py.user.next
Так он же пишет не про границы массива, а про синтаксис. Ты там написал про выход за границы массива, я стал искать и его не увидел.
Ты невнимателен.
По-старому было
int td[4][3]
А по-новому предлагает
int[3][4] td
-измерения поменялись местами.
Поскольку тип пишется слева, запись означает
"4 массива типа int[3]".
Выход за рамки размерности уже является выходом за ганицы массива, а не только лишь покидание границ выделенной памяти.
Когда рантайм проверки излишни, можно пометить блок как @trusted и их не будет, или скомпилировать всё с соответствующими ключами.
А так, вот оно:
module main;

int[3][4] td;

int main()
{
td[2][3] = 1;
return 0;
}
ldc2  -w -g    -I/usr/import -c hello.d -of=obj/Debug/hello.o
hello.d(7): Error: array index 3 is out of bounds td[2][0 .. 3]

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version