Ich möchte die tief verschachtelte Verzweigung dieses C-Codes reduzieren und frage mich, ob es ein Analysetool gibt, das eine Wahrheitstabelle für die Bedingungen erstellen kann, oder ob ich es manuell analysieren muss? Ich möchte den Code lesbarer und weniger Verzweigungen machen. Meine IDE CLion von JetBrains sagt nichts darüber aus, wie man ein solches Refactoring durchführt. Kann es automatisiert werden? Ich habe nicht versucht, Lint zu verwenden, aber ich könnte es versuchen.
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? */
}
}
}
}
}
Ich konnte die bedingte Verzweigung manuell reduzieren, aber ich habe keine Wahrheitstabelle erstellt. Ich denke, die Codeanalysen sollten mit einer Wahrheitstabelle sagen, welche Zweige wann identisch sind.
Die komplette Funktion sieht heute so aus:
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);
}
Der Code scannt und analysiert ein anderes Programm, deshalb ist es so viel String-Manipulation, Speichern und Vorausschauen auf Zeichen und Zeiger.
Ich hatte einige Erfolge mit einem Tool namens CppCheck über ein Jenkins CI-System. Ich verfolge bedingte Verzweigungen nicht speziell, aber die Anzahl der Überprüfungen , die dieses Tool bietet, ist einen Blick wert. Überprüfen Sie insbesondere den Condition
Teil, der verschiedene Überprüfungen auf Bedingungen auflistet, die immer wahr/falsch sind (einschließlich Wertverfolgung, doppelte Bedingungen, Intervalllogik), aber andere Kategorien führen auch einige möglicherweise nützliche Überprüfungen auf, wie:
Und es ist als Plugin für Ihre IDE verfügbar.
Steve Barnes
goto
- also die Verwendung von keep vermeiden, dann haben Sie nicht gut getan.Niklas Rosenkranz
goto
aber ich mag es eigentlich, weil es so selten ist. Wir können es mit 'break Continue' machen,,
das gefällt mir auch besser als Variablen. In der Tat, wenn Sie in Assembler programmieren, tun Sie diesgoto
oft.Steve Barnes
goto
schlechte Praxis angesehen, da es zu einfach ist , irgendwo außerhalb der Funktion oder Prozedur zu landen - nicht zurückzukehren. Deshalb ist es selten!Niklas Rosenkranz
goto
nur einmal gebraucht, weil ich faul war. Ich verspreche, ich werde es in abreak
oder a änderncontinue
, aber ich mag es nichtboolean
...Ira Baxter
Niklas Rosenkranz
Ira Baxter
Ira Baxter
Niklas Rosenkranz
*(ptr + j)[0]
ist eigentlich sehr konkret der aktuelle Charakter dessen, was gescannt wird,ptr
ist der Anfang der Pipe und j ist der Offset. 0 bedeutet erstes Zeichen des Arguments. Spezifikation [hier](pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html).Ira Baxter
Niklas Rosenkranz
fork
von und verwendetexec
wird, aber Schleifen sind für mich schneller und einfacher zu codieren als Rekursion. Ich denke, die Idee ist gut, eine Wahrheitstabelle für die Bedingungen zu erstellen, um zu sehen, ob etwas immer ist or never true, weil ich auf dieser detaillierten Ebene von C-Zeigern bisher keine Erfahrung habe, aber ich arbeite daran. Sie können das gesamte Repository für dieses Ding finden, das meine eigene Shell ähnlichsash
oder istdash
. Es ist interessant, dass Valgrind das kann finde so viel über den Arbeitsspeicher, dass ich einen Test geschrieben habe, der Valgrind verwendet.Ira Baxter
Thomas Weller
StefanS
StefanS
Ira Baxter
Niklas Rosenkranz
while
Schlüsselwortexpr(A)::= WHILE LPAR expr(B) RPAR expr(C). {printf("test"); }
, aber die Testzeichenfolge wird nicht gedruckt. Mein Code wurde unordentlich und ich versuche stattdessen, eine Grammatik zu erstellen.Ira Baxter
Niklas Rosenkranz
while
Schlüsselwort basierend auf dem einfachen Taschenrechner fast ausführen. Jetzt sagen sie heute bei der Codeüberprüfung, dass mein Code "viel" Verbesserung zeigt: codereview.stackexchange.com/questions/128149/…