Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo / 25 сообщений из 27, страница 1 из 2
07.04.2014, 09:08
    #38606866
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Здравствуйте.
Читал сегодня K&R 6.3, разочаровался в использованном алгоритме бинарного поиска для решения поставленной задачи в той главе. Потому решил сегодня(завтра продолжу K&R) почитать книгу о которой я писал ранее. Приятно было читать её с пониманием. Первый раз я прочитал что-то, и понял 80-90 процентов. (например приведение printf к void пока не очень понятно, вероятно ранее это было необходимо). Разобрал первый пример в книге, это работа программы echo. Ниже привожу оригинальный код.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
/*	$NetBSD: echo.c,v 1.7 1997/07/20 06:07:03 thorpej Exp $	*/

/*
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT(
"@(#) Copyright (c) 1989, 1993\n\
	The Regents of the University of California.  All rights reserved.\n");
#endif /* not lint */

#ifndef lint
#if 0
static char sccsid[] = "@(#)echo.c	8.1 (Berkeley) 5/31/93";
#else
__RCSID("$NetBSD: echo.c,v 1.7 1997/07/20 06:07:03 thorpej Exp $");
#endif
#endif /* not lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int	main __P((int, char *[]));

int
main(argc, argv)
	int argc;
	char *argv[];
{
	int nflag;

	/* This utility may NOT do getopt(3) option parsing. */
	if (*++argv && !strcmp(*argv, "-n")) {
		++argv;
		nflag = 1;
	}
	else
		nflag = 0;

	while (*argv) {
		(void)printf("%s", *argv);
		if (*++argv)
			putchar(' ');
	}
	if (!nflag)
		putchar('\n');
	exit(0);
}



В целом, я понял как он работает. И потому решил его переписать. Исправил три вещи, и у меня одна маленькая помарка. Может быть вам самим будет интересно подумать что тут можно исправить, потому мой код пока скрыт.

SS_echo
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#include <stdio.h>
#include <string.h>

//echo
int main(int argc, char* argv[])
{
	//проверка на то что первый аргументом будет "-n" (отмена переноса строки после вывода аргументов)
	int nflag = (*++argv && !strcmp(*argv, "-n") && ++argv) ? 1 : 0;//хочу обнять эту строчку, нравится мне она :p
	// две минуты думал как сделать сдвиг по argv если есть "-n" :p
	while (*argv)
	{
		printf("%s ", *argv);
		argv++;
	}
	if (!nflag) printf("\n");
	return 0;
}



1. Взгляните на то, как неудачно происходит инициализация nflag. Даже в самом простом приближении можно было написать:
Код: plaintext
1.
2.
а. int nflag=0;
б. проверка с возможной инициализацией в единицу


В моей строке, int nflag = (*++argv && !strcmp(*argv, "-n") && ++argv), мне жутко понравилась часть выделенная красным цветом. Мне кажется я сделал правильно, но мало ли, лучше узнать ваше мнение.

2. Далее идут while и if для вывода пробела, как видно, я их объединил. Да, в конце выводится лишний пробел, но я уверен что каретку можно вернуть на одну позицию, правда не знаю как.

3. Не понравилось что где-то для вывода используется putchar, а где-то printf.


Также, как вам следующая строка из книги:
Спинеллис Анализ кодаОбратите внимание, что при равенстве сравниваемых строк функция strcmp возвращает не совсем логичное 0,..., поэтому во многих программах определяется макрос STREQ...


Это мне не понравилось, если даже я понимаю что возврат 0 очень даже логичен(мы то с вами знаем как работает эта функция), а уж опытные программисты и подавно знают! И писать для этого макрос ? Нееет, чушь собачья, скажу так. Разве нет ?

Всё ли нормально в коде ?
...
Рейтинг: 0 / 0
07.04.2014, 10:47
    #38606955
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercuryВ моей строке, int nflag = (*++argv && !strcmp(*argv, "-n") && ++argv), мне жутко понравилась часть выделенная красным цветом. Мне кажется я сделал правильно, но мало ли, лучше узнать ваше мнение.
Оно сработает, но абсолютно нечитаемо - надо вникать что имелось в виду.
Тогда как исходный пример имеет очень простой и понятный код.
SashaMercury2. Далее идут while и if для вывода пробела, как видно, я их объединил. Да, в конце выводится лишний пробел, но я уверен что каретку можно вернуть на одну позицию, правда не знаю как.

3. Не понравилось что где-то для вывода используется putchar, а где-то printf.
То что вам что-то не нравится это еще можно как-то с натяжкой объяснить.
Но то что вы при исправлении внесли изменения в форматирование вывода - это недопустимо.
...
Рейтинг: 0 / 0
07.04.2014, 11:25
    #38607001
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercury,

Про инициализацию nflag.
Это язык C! Ты вообще в курсе, что в языке С инициализировать можно только глобальные и статические переменные, автоматические — нельзя. Это в классическом С, достандартовом.
Сейчас уже более новые стандарты есть, сейчас это глупое ограничение снято, как и необходимость объявлять переменные только в начале блока.
...
Рейтинг: 0 / 0
07.04.2014, 11:27
    #38607004
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercury,

то мне не понравилось, если даже я понимаю что возврат 0 очень даже логичен(мы то с вами знаем как работает эта функция), а уж опытные программисты и подавно знают! И писать для этого макрос ? Нееет, чушь собачья, скажу так. Разве нет ?


Да, согласен полностью.
...
Рейтинг: 0 / 0
07.04.2014, 15:52
    #38607399
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Что не так с инициализацией ? Объясните пожалуйста подробней
...
Рейтинг: 0 / 0
07.04.2014, 15:54
    #38607403
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercuryЧто не так с инициализацией ? Объясните пожалуйста подробней
MasterZiv хотел сказать, что в каких-то древних компиляторах нельзя было инициализировать локальные переменные при объявлении.
К счастью таких компиляторов уже давно не существует и вы можете спать спокойно :)
...
Рейтинг: 0 / 0
07.04.2014, 15:57
    #38607408
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Понятно теперь. Спасибо
...
Рейтинг: 0 / 0
07.04.2014, 15:58
    #38607410
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Я об этом не знал. "Не в курсе" был
...
Рейтинг: 0 / 0
08.04.2014, 03:01
    #38607815
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Здравствуйте. Ещё раз про strcmp.
Спинеллис Анализ кодаstrcmp возвращает не совсем логичное 0, поэтому во многих программах на С определяется макрос STREQ, который возвращает 1, если сравниваемые строки равны. Часто, эта операция оптимизируется путём явного сравнения первых двух символов:
Код: plaintext
1.
#define STREQ(a,b) ((*a)==(*b) && strcmp((a),(b))==0)




С виду лишняя операция сравнения, за счёт чего происходит оптимизация ?
...
Рейтинг: 0 / 0
08.04.2014, 07:31
    #38607864
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercury,

Убирается оверхед на вызов функции для одного из частных случаев.
...
Рейтинг: 0 / 0
08.04.2014, 08:45
    #38607910
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly Moskovsky, мне не очень понятно. В каком из случаев, и каким образом мы экономим ? или подскажите где мне почитать если вы уже всё объяснили что могли, а я просто не понимаю
...
Рейтинг: 0 / 0
08.04.2014, 09:06
    #38607923
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercury,

Вот это условие *a==*b не срабатывает, когда первые символы строк не совпадают или когда одна из строк пустая, а другая - нет.
В этом случае вызова strcmp не происходит: левый операнд && - false, и вычислять правый нет смысла (так называемый Short-circuit_evaluation ).

За счет того, что в этом случае не происходит вызова strcmp, убираются расходы на сам вызов (машинные команды call, ret), плюс расходы на копирование аргументов и результата.

ЗЫ. Но современные компиляторы умеют сами оптимизировать strcmp и аналоги, так что смысла в такой ручной оптимизации нет. Да и не такие уж там и большие расходы на вызов :)
...
Рейтинг: 0 / 0
08.04.2014, 09:14
    #38607928
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly Moskovskyлевый операнд && - false, и вычислять правый нет смысла (так называемый Short-circuit_evaluation ).
Тут уточнение. Не только "нет смысла", но и согласно стандарту именно так и надо вычислять.
...
Рейтинг: 0 / 0
08.04.2014, 09:15
    #38607931
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercuryAnatoly Moskovsky, мне не очень понятно. В каком из случаев, и каким образом мы экономим ? или подскажите где мне почитать если вы уже всё объяснили что могли, а я просто не понимаю
Это уже из области ассемблера, т.е. того машинного кода в который компилятор превращает этот Си код.
Вызов функции имеет накладные расходы. Схематично так происходит: сохраняется в стек адреса возврата, переход по адресу функции, сохранение текущего состояния регистров в стек, выполнение кода функции, и дальше в обратном порядке.
Для сравнения двух значений всего этого не происходит.

Хотя на сегодня это не актуально, компиляторы сами заменяют вызов функции на ее код (почитай про inline функции). В таком случае доп.проверка лишний тормоз, пусть незначительный.
...
Рейтинг: 0 / 0
08.04.2014, 10:09
    #38607992
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly Moskovsky Но современные компиляторы умеют сами оптимизировать strcmp

1. при трансляции, компиляторы распознают места в которых можно добавить схему оптимизирующую вычисление данного участка кода, и добавляют самостоятельно тот код что я мог бы добавить(сравнение первых символов например) ?

2. В данном конкретном случае, если допустить что strcmp будет вызываться только в этом месте в программе (либо добавлять везде перед вызовом strcmp проверку на равенство первых символов), и также при исключении варианта когда обе строки пустые, есть ли смысл начать сравнение строк в функции начиная со вторых символов символов(изменить код функции в данном конкретном случае) ?

Dima_TВызов функции имеет накладные расходы. Схематично так происходит: сохраняется в стек адреса возврата, переход по адресу функции, сохранение текущего состояния регистров в стек, выполнение кода функции, и дальше в обратном порядке.
Для сравнения двух значений всего этого не происходит.

Хотя на сегодня это не актуально, компиляторы сами заменяют вызов функции на ее код (почитай про inline функции). В таком случае доп.проверка лишний тормоз, пусть незначительный.


Это конечно не математика, но программирование нравится мне всё больше(хотя функциональный анализ на первом месте) :p Может быть я где-то слышал про то что вместо for лучше написать 10 строчек, ибо быстрее, но про такое слышу первый раз.

Вы мне прямо настроение подняли, так здорово это узнавать всё это, и понимать
...
Рейтинг: 0 / 0
08.04.2014, 10:10
    #38607995
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly Moskovsky Но современные компиляторы умеют сами оптимизировать strcmp

Вы наверное имели ввиду то что Дмитрий мне объяснял позже !
...
Рейтинг: 0 / 0
08.04.2014, 12:24
    #38608269
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly MoskovskySashaMercuryЧто не так с инициализацией ? Объясните пожалуйста подробней
MasterZiv хотел сказать, что в каких-то древних компиляторах нельзя было инициализировать локальные переменные при объявлении.
К счастью таких компиляторов уже давно не существует и вы можете спать спокойно :)


Ребята, на даты-то поглядите:

Код: plaintext
1.
2.
/*	$NetBSD: echo.c,v 1.7 1997/07/20 06:07:03 thorpej Exp $	*/
 * Copyright (c) 1989, 1993
...
Рейтинг: 0 / 0
08.04.2014, 14:31
    #38608537
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
MasterZivРебята, на даты-то поглядите:

Код: plaintext
1.
/*	$NetBSD: echo.c,v 1.7 1997/07/20 06:07:03 thorpej Exp $	*/
 * Copyright (c) 1989, 1993

А что на них смотреть? Уже в 89 не было компиляторов не умеющих инициализаторы в локальных переменных.
Да и по большому счету их вообще никогда не было. Были на ранних этапах недоделанные компиляторы, которые поддерживали инициализаторы только для скаляров. Отсюда и пошел миф.
...
Рейтинг: 0 / 0
03.07.2014, 02:44
    #38686348
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Код: plaintext
1.
2.
3.
4.
5.
	/* This utility may NOT do getopt(3) option parsing. */
	if (*++argv && !strcmp(*argv, "-n")) {
		++argv;
		nflag = 1;
	}



Как вы думаете, почему в этом участке кода нельзя использовать функцию getopt ?(вопрос от Дэйва Томаса)
Я думал некоторое время, но так и не понял почему. Возможно потому что getopt не принадлежит Си, и по-моему это POSIX функция. Хотя странно, сейчас открыл ссылку wiki , а тут первая строка "getopt is a C library function used to parse command-line options."
...
Рейтинг: 0 / 0
03.07.2014, 05:01
    #38686355
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercury,

Потому что getopt съедает "--" в аргументах, а echo согласно стандарту должен уметь его печатать.
...
Рейтинг: 0 / 0
03.07.2014, 12:17
    #38686686
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly MoskovskyMasterZivРебята, на даты-то поглядите:

Код: plaintext
1.
/*	$NetBSD: echo.c,v 1.7 1997/07/20 06:07:03 thorpej Exp $	*/
 * Copyright (c) 1989, 1993

А что на них смотреть? Уже в 89 не было компиляторов не умеющих инициализаторы в локальных переменных.
Да и по большому счету их вообще никогда не было. Были на ранних этапах недоделанные компиляторы, которые поддерживали инициализаторы только для скаляров. Отсюда и пошел миф.
Я-бы проверил факт инициализации переменных. Что там с Сашки за компиллятор - бох его знает.
...
Рейтинг: 0 / 0
03.07.2014, 13:16
    #38686762
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercuryКак вы думаете, почему в этом участке кода нельзя использовать функцию getopt ?(вопрос от Дэйва Томаса)
Я думал некоторое время, но так и не понял почему. Возможно потому что getopt не принадлежит Си, и по-моему это POSIX функция. Хотя странно, сейчас открыл ссылку wiki , а тут первая строка "getopt is a C library function used to parse command-line options."


getopt -- это отдельная библиотека, не стандартная (ANSI C), описанная в POSIX, которая выпущена под лицензией GNU.
...
Рейтинг: 0 / 0
07.07.2014, 06:43
    #38689039
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Anatoly MoskovskySashaMercury,

Потому что getopt съедает "--" в аргументах, а echo согласно стандарту должен уметь его печатать.

Действительно так. Спасибо.
Мне не нравится эта функция. Даже то как они её описывают
Код: plaintext
1.
int getopt(int argc, char* const *argv, const char* optstring)



Зачем вносить путаницу и называть параметры argc и argv, если это обыкновенный парсер любой строки, и не обязательно параметров точки инициализации. И не самое хорошее описание функции. И лучше уж тогда не getopt, а findopt. Плюс к чему это сжирание лишнего dash.

Вы пользуетесь этой функцией ? Нравится ли она вам ?
...
Рейтинг: 0 / 0
07.07.2014, 07:01
    #38689041
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Читаю книгу дальше, смотрите какой всё-таки красивый и чудеснейший код . Я им и сам уже пользовался кучу раз, но он настолько мне нравится, что я смотрю на него и смотрю
Код: plaintext
1.
2.
while((c=getc(pf))!=EOF)
      putc(c,active)



И отличный комментарий к нему из книги:
СпинеллисДалее приведён типичный пример такой конструкции, которая копируют символы из файлового потока pf в файловый поток active до тех пор, пока не достигается конец потока pf.


Кажется такое простое предложение, но даже оно мне кажется прекрасным.
...
Рейтинг: 0 / 0
07.07.2014, 13:42
    #38689393
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
SashaMercuryЗачем вносить путаницу и называть параметры argc и argv, если это обыкновенный парсер любой строки, и не обязательно параметров точки инициализации. И не самое хорошее описание функции. И лучше уж тогда не getopt, а findopt. Плюс к чему это сжирание лишнего dash.
Это не сжирание лишнего dash. Это совершенно корректное стандартное поведение при парсинге опций.
Если у нас в есть такой вызов
Код: plaintext
1.
cmd -a -b -c -- -d -f 


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

С другой стороны для echo другие правила
Код: plaintext
1.
echo -a -b -c -- -d -f 


это должно напечатать " -a -b -c -- -d -f " а не рассматриваться как опции (кроме нескольких исключений).

И getopt не парсер любой строки, а именно опций переданных в main поэтому ее параметры названы очень удачно, как и имя.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo / 25 сообщений из 27, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]