Я хочу уменьшить глубокое вложенное ветвление этого кода C, и мне интересно, есть ли инструмент анализа, который может составить таблицу истинности для условий, или мне придется анализировать ее вручную? Я хотел бы сделать код более читабельным и менее разветвленным. В моей IDE CLion от JetBrains ничего не сказано о том, как выполнить такой рефакторинг. Можно ли его автоматизировать? Я не пробовал использовать Lint, но я мог бы попробовать.
if (ptr + j) {
if (*(ptr + j)[0] == '{') {
keep = true;
}
if (testFn(*(ptr + j))) { /* test for last char */
string[i][j - p] = concat(*pString1, *(ptr + j));
keep = false;
free(*pString1);
goto mylabel;
}
if (keep) {
*pString1 = concat(*pString1, *(ptr + j));
*pString1 = concat(*pString1, " ");
p++;
} else {
b1 = false;
int q = j;
for (e = 0; *(ptr + q + e); e++) { /* step through the string */
b1 = true;
if (*(ptr + e + q)) {
*pString = concat(*pString, *(ptr + e + q));
*pString = concat(*pString, " ");
}
j = e;
}
if (makeArgs(*pString, &argc, (const char ***) &argv, pipe, i, h)) {
write_command(&w, argv, string[w]);
w++;
} else {
if (!b1) { /* no args (?) */
for (int r = 0; argv[r] != NULL; r++) {
string[i][r] = argv[r]; /* is this necessary? */
}
}
}
}
}
Мне удалось уменьшить условное ветвление вручную, но я не сделал таблицу истинности. Я думаю, что анализ кода должен сказать, какие ветки идентичны и когда с таблицей истинности.
Полная функция сегодня выглядит так:
static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command structcommand[15];
char **argv = 0;
int argc = 1;
bool pipe = false;
char *string[z][z];
char *pString3[40];
char *pString2[40];
int n = 0;
char **ptr1;
char string1[z];
bool keep = false;
char *pString1[z];
char *pString[z];
*pString1 = "\0";
*pString = "\0";
char *temp = {'\0'};
int w = 0;
bool quote = false;
int rrs[256];
int j = 0;
int i;
int p = 0;
char **ptr;
int count = 0;
char *cmdtmp;
bool b1 = false;
int y = 0;
i = 0;
int h = 0;
char *str;
char *freeme[75][75];
char **dealloc[75];
char **dealloca[75][75];
int acount[128];
nullterminate(string);
int rr = 0;
for (z = 0; z < 128; z++) {
acount[z] = -1;
}
for (int f = 0; f < 75; f++) {
dealloc[f] = NULL;
for (z = 0; z < 75; z++) {
freeme[f][z] = NULL;
}
}
if (cmd) {
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)) {
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
cmdtmp = strdup(cmd);
ptr1 = str_split(pString3, cmdtmp, '|');
if (strstr(cmd, "|") == NULL) { /* not a pipeline */
makeArgs(cmd, &argc, (const char ***) &argv, pipe, 0, 0);
write_argument(&argc, structcommand, argv, string[0]);
n++;
}
else {
for (i = 0; *(ptr1 + i); i++) { /* loop for each pipeline*/
n++;
/* save number of pipelines */
dealloc[n] = NULL;
int e = 0; /* a counter */
*pString = "\0"; /* should malloc and free this? */
strcpy(string1, *(ptr1 + i));
if ((string1[0] != '\0') &&
!isspace(string1[0])) { /* this is neither the end nor a new argument */ /* BSD bug? check*/
ptr = str_split(pString2, *(&string1), ' '); /* split the string at the arguments */
dealloc[rr] = ptr;
rr++;
h = 0;
for (j = 0; *(ptr + j); j++) { /* step through the arguments */
dealloca[n][n - 1] = NULL;
/* the pipeline is in cmdtmp and the argument/program is in ptr[i] */
if (ptr + j && !quote && strstr(*(ptr + j), "'")) { /* is quote? */
quote = true;
strcpy(temp, *(ptr + j)); /* point where quoted piipelines crash */
if (y < 1) {
y++;
}
}
while (quote) {
if (*(ptr + j) && strstr(*(ptr + j), "'")) { /* end of quote */
quote = false;
if (y < 1) {
string[i][j] = strcpy(temp, *(ptr + j));
}
y = 0;
}
else if (*(ptr + j)) { /* read until end of quote */
string[i][j] = temp;
continue;
} else {
quote = false;
break;
}
}
if (ptr + j) { ;
if (*(ptr + j)[0] == '{') {
keep = true;
}
if (testFn(*(ptr + j))) { /* test for last char */
string[i][j - p] = concat(*pString1, *(ptr + j));
keep = false;
free(*pString1);
continue;//goto mylabel;
}
if (keep) {
str = concat(*pString1, *(ptr + j));
*pString1 = concat(str, " ");
free(str);
p++;
} else {
b1 = false;
int q = j;
freeme[i][0] = *pString;
for (e = 0; *(ptr + q + e); e++) { /* step through the string */
b1 = true;
if (*(ptr + e + q)) {
str = concat(*pString, *(ptr + e + q));
*pString = concat(str, " "); /* how to free() ? */
free(str);
freeme[i][e] = *pString;
}
j = e; /* adjust the counter */
}
if (makeArgs(freeme[i][e - 1], &argc, (const char ***) &argv, pipe, i, h)) {
write_command(&w, argv, string[w]);
w++;
for (int qwe = 0; qwe < argc; qwe++) {
dealloca[n - 1][qwe] = &argv[qwe];
}
acount[n - 1] = argc;
} else {
if (!b1) { /* no args (?) */
for (int r = 0; argv[r] != NULL; r++) {
string[i][r] = argv[r]; /* is this necessary? */
}
}
}
}
}
}
bool boo = false;
dump_argv((const char *) "d", argc, argv, boo);
}
}
}
for (i = 0; i < n; i++) {
structcommand[i].argv = string[i];
for (j = 0; string[i][j] != NULL; j++) {
if (string[i] != NULL) {
}
}
}
free(cmdtmp);
if (ptr1) {
int i;
for (i = 0; *(ptr1 + i); i++) {
free(*(ptr1 + i));
}
printf("\n");
free(ptr1);
}
fflush(NULL);
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the string.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(n, structcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
}
for (i = 0; i < n; i++) {
for (j = 0; string[i][j] != NULL; j++) {
if (string[i] != NULL) {
if (string[i][j])
free(string[i][j]);
}
}
}
int z;
for (int f = 0; f < n; f++) {
if (f > 0) {
}
for (z = 0; freeme[f][z]; z++) {
free(freeme[f][z]);
}
}
size_t idx;
for (int f = 0; n > 1 && f < n; f++) {
for (idx = 0; *(dealloc[f] + idx) != NULL; idx++) {
free(*(dealloc[f] + idx));
}
free(dealloc[f]);
}
return WEXITSTATUS(status);
}
Код сканирует и анализирует другую программу, поэтому так много манипуляций со строками, сохранения и просмотра символов и указателей.
Я добился определенного успеха, используя инструмент под названием CppCheck через систему Jenkins CI. Я специально не отслеживаю условные ветки, но количество проверок , которые предоставляет этот инструмент, того стоит. В частности, проверьте Condition
часть, в которой перечислены различные проверки условий, которые всегда являются истинными/ложными (включая отслеживание значений, повторяющиеся условия, логику интервалов), но в других категориях также перечислены некоторые, возможно, полезные проверки, такие как:
И он доступен в виде плагина для вашей IDE.
Стив Барнс
goto
- значит, избегая использования keep, вы не преуспели.Никлас Розенкранц
goto
но мне это действительно нравится, потому что это так редко. Мы можем сделать это с помощью «break,
continue», что мне также нравится больше, чем переменные. На самом деле, если вы программируете на ассемблере, вы делаете этоgoto
часто.Стив Барнс
goto
где-то за пределами функции или процедуры - не возвращаться. Вот почему это редкость!Никлас Розенкранц
goto
только один раз, потому что был ленив. Я обещаю, что поменяю его на abreak
или acontinue
, но мне не нравитсяboolean
...Ира Бакстер
Никлас Розенкранц
Ира Бакстер
Ира Бакстер
Никлас Розенкранц
*(ptr + j)[0]
на самом деле очень конкретный текущий символ того, что сканируется,ptr
является началом канала, а j - смещением. 0 означает первый символ аргумента. Спецификация [здесь] (pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html).Ира Бакстер
Никлас Розенкранц
fork
иexec
, но циклы для меня быстрее и проще кодировать, чем рекурсия. Я думаю, что идея хороша, чтобы сделать таблицу истинности для условий, чтобы увидеть, всегда ли что-то или никогда не верно, потому что я пока не знаком с этим подробным уровнем указателя C, но я работаю над этим. Здесь вы можете найти весь репозиторий для этой вещи, которая является моей собственной оболочкой, похожей наsash
илиdash
, Интересно, что Valgrind может найти так много об оперативной памяти, я написал тест, который использует Valgrind.Ира Бакстер
Томас Веллер
СтефанС
СтефанС
Ира Бакстер
Никлас Розенкранц
while
ключевого словаexpr(A)::= WHILE LPAR expr(B) RPAR expr(C). {printf("test"); }
, но тестовая строка не печатается. Мой код запутался, и вместо этого я пытаюсь сделать грамматику.Ира Бакстер
Никлас Розенкранц
while
ключевое слово на основе простого калькулятора. Сегодня на обзоре кода они говорят, что мой код показывает «много» улучшений: codereview.stackexchange.com/questions/128149/…