powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
25 сообщений из 27, страница 1 из 2
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38606866
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте.
Читал сегодня 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
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38606955
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryВ моей строке, int nflag = (*++argv && !strcmp(*argv, "-n") && ++argv), мне жутко понравилась часть выделенная красным цветом. Мне кажется я сделал правильно, но мало ли, лучше узнать ваше мнение.
Оно сработает, но абсолютно нечитаемо - надо вникать что имелось в виду.
Тогда как исходный пример имеет очень простой и понятный код.
SashaMercury2. Далее идут while и if для вывода пробела, как видно, я их объединил. Да, в конце выводится лишний пробел, но я уверен что каретку можно вернуть на одну позицию, правда не знаю как.

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

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

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


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




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

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

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

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

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

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

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

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

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

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


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

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

Вы наверное имели ввиду то что Дмитрий мне объяснял позже !
...
Рейтинг: 0 / 0
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38608269
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38608537
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivРебята, на даты-то поглядите:

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

А что на них смотреть? Уже в 89 не было компиляторов не умеющих инициализаторы в локальных переменных.
Да и по большому счету их вообще никогда не было. Были на ранних этапах недоделанные компиляторы, которые поддерживали инициализаторы только для скаляров. Отсюда и пошел миф.
...
Рейтинг: 0 / 0
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38686348
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38686355
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercury,

Потому что getopt съедает "--" в аргументах, а echo согласно стандарту должен уметь его печатать.
...
Рейтинг: 0 / 0
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38686686
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38686762
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryКак вы думаете, почему в этом участке кода нельзя использовать функцию getopt ?(вопрос от Дэйва Томаса)
Я думал некоторое время, но так и не понял почему. Возможно потому что getopt не принадлежит Си, и по-моему это POSIX функция. Хотя странно, сейчас открыл ссылку wiki , а тут первая строка "getopt is a C library function used to parse command-line options."


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

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

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



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

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



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


Кажется такое простое предложение, но даже оно мне кажется прекрасным.
...
Рейтинг: 0 / 0
Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
    #38689393
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
25 сообщений из 27, страница 1 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / Анализ программного кода на примере проектов Open Source 2.1 Пример полной программы /echo
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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