Объясните код в C

58
9

Я хочу понять этот код специально parse_args. Этот код является простой оболочкой для запуска базовой команды linux в качестве pwd cat и так далее. Я хочу понять, как работает parse_args.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define BUFFER_SIZE 1<<16
#define ARR_SIZE 1<<16

void parse_args(char *buffer, char** args,
size_t args_size, size_t *nargs)
{
char *buf_args[args_size]; /* You need C99 */
char **cp;
char *wbuf;
size_t i, j;

wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;

for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}

for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}

*nargs=j;
args[j]=NULL;
}

int main(int argc, char *argv[], char *envp[]){
char buffer[BUFFER_SIZE];
char *args[ARR_SIZE];

int *ret_status;
size_t nargs;
pid_t pid;

while(1){
printf("$ ");
fgets(buffer, BUFFER_SIZE, stdin);
parse_args(buffer, args, ARR_SIZE, &nargs);

if (nargs==0) continue;
if (!strcmp(args[0], "exit" )) exit(0);
pid = fork();
if (pid){
printf("Waiting for child (%d)\n", pid);
pid = wait(ret_status);
printf("Child (%d) finished\n", pid);
} else {
if( execvp(args[0], args)) {
puts(strerror(errno));
exit(127);
}
}
}
return 0;
}

спросил(а) 2020-03-25T20:05:42+03:00 5 месяцев, 3 недели назад
1
Решение
91

Это весело. Функция разделяет буфер на массив строк, где он попадает в разделитель белого пробела.

void parse_args(char *buffer, char** args, 
size_t args_size, size_t *nargs)
{
char *buf_args[args_size]; /* You need C99 */
char **cp;
char *wbuf;
size_t i, j;

Код инициализации...

    wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;

Установите все указатели на начало буфера

    for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){

Установите указатель записи cp чтобы указать на первый элемент в массиве buf_args.

Установите * cp в следующий экземпляр маркера не-whitespace в буфере и wbuf в его конечную позицию

    if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;

Остановитесь, когда strsep вернул NULL или когда он указывает на конец буфера или когда он указывает за конец buf_args []

    }

for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}

Этот цикл создает сжатую копию массива buf_args []: он копирует только аргументы, которые не являются пустыми. Я предполагаю, что это может произойти, если в исходном буфере есть серия последовательных символов пробела.

    *nargs=j;
args[j]=NULL;
}

Поместите NULL в конец выходного массива и задайте выходной аргумент nargs.

ответил(а) 2020-03-25T20:21:07.852011+03:00 5 месяцев, 3 недели назад
81

Хорошо, так что пройдите через некоторые из строк в parse args

wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;

Это устанавливает wbuf для указания того, что находится в buffer. Он также устанавливает первый указатель в массиве buf_args в buffer. И он делает то же самое для первого элемента args.

for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}

Функция strsep просматривает wbuf для пространства разделителей, новой строки или вкладки и возвращает указатель на начало токена, а wbuf обновляется до конца токена. Если в строке больше разделителей, функция возвращает NULL. Итак, средняя часть оператора for продолжается до тех пор, пока *cp равным NULL.

Итак, указатель cp первоначально указывает на строку (указатель) в buf_args[0]. Функция разделителя строк заполняет *cp адресом адресата. Затем проверка if проверяет 1), если цикл for превысил емкость buf_args, проверив, превысил ли указатель cp последний элемент и 2), если первым символом возвращенного токена является конец символа строки.

Примечание: я думаю, что строка должна быть *(*cp) != '\0'?

for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}

Затем он перебирает все buf_args пока не найдет NULL. Если строка, на которую указывает buf_args, длиннее 0, т. buf_args Имеет символы, массив args получает копию указателя на токен.

*nargs=j;
args[j]=NULL;

Последний элемент args после заполненных записей устанавливается NULL. И значение nargs устанавливается на длину числа заполненных элементов в массиве args.

ответил(а) 2020-03-25T20:05:42+03:00 5 месяцев, 3 недели назад
70

в этом разделе кода

for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}

проверьте массив wbuf для разделителей "\n\t" (сначала пробел) и сохраните его позиции в buf_args, затем в

for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}

секция exrtacting аргументов в массив args, чтобы получить результат из функции

ответил(а) 2020-03-25T20:05:42+03:00 5 месяцев, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема