Как я могу перейти к значению строки в C? - PullRequest
2 голосов
/ 09 января 2012

Я программирую робота на C, и у меня возникла проблема, которую я не могу понять.

Единственный способ решить эту проблему - использовать множество goto операторов. Я пытаюсь найти способ сэкономить, записывая более 100 goto точек и утверждений, а также операторы if и т. Д., И мне интересно, есть ли способ перейти к значению строки. например -

string Next = "beginning";
goto Next;
beginning:

Есть ли способ goto значение Next или подставить значение Next в оператор goto?

Если есть способ сделать это, тогда я смогу просто изменить значение Next для каждой команды движения, а затем goto независимо от значения строки Next.

Другими словами, просто преобразовав строку в goto идентификатор или подставив ее вместо единицы.

Спасибо за помощь!

-EDIT-

Многие из вас, ребята, предлагают использовать операторы switch. Я не уверен, что это сработает из-за того, как я его запрограммировал. Структура программы здесь - кстати, этот код включает в себя только то, что у меня есть на самом деле, мой реальный код до сих пор превышает 500 строк. Кроме того, команды вождения в основном упрощены. но основная концепция здесь, легче понять, чем то, что я имел бы.

task main()
{
  //integer list
  int forwardDrivingSelector = 0;
  int backwardDrivingSelector = 0;
  int rightRotatingSelector = 0;
  string nextCommand;
  int waitTime = 0;
  int countup = 0;

  //driving commands

  driveForward:
  while(forwardDrivingSelector == 1)
  {
    motor[leftMotor] = 127;
    motor[rightMotor] = 127;
    countup++;
    wait1Msec(1);
    if(countup == waitTime)
    {
      countup = 0;
      goto nextCommand;
    }
  }
  driveBackward:
  while(backwardDrivingSelector == 1)
  {
    motor[leftMotor] = -127;
    motor[rightMotor] = 127;
    countup++;
    wait1Msec(1);
    if(countup == waitTime)
    {
      countup = 0;
      goto nextCommand;
    }
  }
  rightRotate:
  while(rightRotatingSelector == 1)
  {
    motor[leftMotor] = 127;
    motor[rightMotor] = -127;
    countup++;
    wait1Msec(1);
    if(countup == waitTime)
    {
      countup = 0;
      goto nextCommand;
    }
  }

  //autonomous driving code

  //first command, drive forward for 1000 milliseconds
  forwardDrivingSelector = 1;
  nextCommand = "secondCommand";
  waitTime = 1000;
  goto driveForward;

  secondCommand:
  forwardDrivingSelector = 0;

  //second command, rotate right for 600 milliseconds
  rightRotatingSelector = 1;
  nextCommand = "thirdCommand";
  waitTime = 600;
  goto rightRotate;

  thirdCommand:
  rightRotatingSelector = 0;

  //third command, drive backwards for 750 milliseconds
  backwardDrivingSelector = 1;
  nextCommand = "end";
  waitTime = 750;
  goto driveBackward;

  end:
  backwardDrivingSelector = 0;

}

так. как это работает у меня есть список целых чисел, включая селекторы управляющих команд, целые числа countup и waitTime, а также строку, о которой я говорил, nextCommand. Далее следуют водительские команды. в моем реальном коде у меня около 30 команд, и все они подключены к пульту дистанционного управления, и его более 400 строк предназначены только для команд управления. Далее идет автономный код. причина, по которой я настроил это так, состоит в том, что автономная часть кода будет короткой, простой и точной. в значительной степени, чтобы добавить команду к коду управления, вы включаете селектор, сообщаете строке nextCommand, какой будет следующая команда, устанавливаете waitTime (то есть, сколько времени она выполняет команду, в миллисекундах), затем вы делаете код goto команда вождения, которую вы вводите. команда вождения определяет количество времени, которое вы ввели, затем выполняет команду nextCommand;

Теоретически это работало бы, если бы был способ заставить оператор goto интерпретировать строку как идентификатор, чтобы ее можно было изменить.

Есть около 4 простых способов, которые я могу придумать прямо сейчас, которые могли бы легко обойти это, но они сделали бы код действительно очень длинным и беспорядочным.

Теперь, когда у вас есть лучшее понимание моего вопроса, есть еще какие-то комментарии? :)

кстати - я использую программу под названием robotC, и я программирую робота vex. так что я ДОЛЖЕН использовать простой, базовый, C, и я не могу использовать какие-либо дополнения или что-нибудь ... что является еще одной причиной, по которой это сложно, потому что я не могу иметь несколько классов и тому подобное ...

Ответы [ 7 ]

4 голосов
/ 09 января 2012

Вместо goto я бы назвал одну из 100 функций. Хотя C не будет выполнять преобразование из строки в функцию для вас, довольно просто использовать отсортированный массив структур:

struct fn {
    char name[whatever];
    void (*func)(void);
};

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

Также обратите внимание, что многие реальные системы предоставляют такие вещи, как GetProcAddress (Windows) или dlsym (Unix / Linux), чтобы справиться с некоторыми задачами для вас.

4 голосов
/ 09 января 2012

В качестве расширения языка C GCC предоставляет функцию, называемую compoted gotos , которая позволяет goto метку, вычисляемую во время выполнения. Тем не менее, Я настоятельно рекомендую вам пересмотреть свой дизайн .

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

1 голос
/ 09 января 2012

Вы должны сделать шаг назад и подумать о других решениях проблемы, которую вы пытаетесь решить. Один из них может выглядеть так:

void DoSomething() {
    printf("Something\n");
}

void DoSomethingElse() {
    printf("Something else\n");
}

void (*nextStep)(void) = NULL;

nextStep = DoSomething;
nextStep();
nextStep = DoSomethingElse;
nextStep();

См. В действии .

1 голос
/ 09 января 2012

Вы думаете об этом неправильно.Каждое из действий, которое вам нужно вызвать, должно быть функцией, тогда вы можете выбрать, какую функцию следует вызывать следующим, проверив «следующую» переменную.

Это может быть строка, как вы упомянули, но вам лучше всего использовать перечислимый тип для создания читабельного, но более эффективного кода.

Альтернативой, хотя, вероятно, и избыточным, будет обеспечение того, чтобы все ваши функции использовали одни и те же параметры и возвращаемые типы, а затем использовали указатель на функцию для отслеживания того, какой фрагмент кода должен быть выполнен следующим.

Небольшой совет: если вам когда-либо кажется, что для достижения определенной цели вам нужно более 1 оператора goto, вы, вероятно, не ищите лучшего решения.

0 голосов
/ 11 января 2012
#define GOTO_HELPER(str, label) \
    if (strcmp(str, #label) == 0) goto label;

#define GOTO(str) do { \
    GOTO_HELPER(str, beginning) \
    GOTO_HELPER(str, end) \
    } while (0)


int main (int argc, char ** argv) {
    GOTO("end");
beginning:
    return 1;
end:
    return 0;
}
0 голосов
/ 09 января 2012

Как насчет switch?Либо используйте int / enum / what, либо проверьте значение строки (например, цикл над ней и strcmp), чтобы выяснить место назначения.

const char *dsts[n_dsts] = {"beginning","middle",...};
...
int i;
for(i = 0; i < n_dsts; i++) if(strcmp(dsts[i]) == 0) break;
switch(i) {
    case 0: // whatever
    case 1: // whatever
    ...
        break;
    default: // Error, dest not found
}
0 голосов
/ 09 января 2012

Во-первых, позвольте мне предвосхитить это, соглашаясь со всеми остальными: это, вероятно, не правильный путь к тому, что вы пытаетесь сделать.В частности, я думаю, что вам, вероятно, нужен конечный автомат, и я рекомендую эту статью для получения инструкций о том, как это сделать.

Тем не менее.,,Вы можете более или менее сделать это, используя оператор switch.Например:

Next = BEGINNING;
HelperLabel:
switch(Next)
{
   case BEGINNING:
     .
     .
     .
     Next = CONTINUING;
     goto HelperLabel;
   case ENDING:
     .
     .
     .
     break;
   case CONTINUING:
     .
     .
     .
     Next = ENDING;
     goto HelperLabel;
}

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

См. http://en.wikipedia.org/wiki/Duff's_device для оригинального, канонического примера использования switch / case в качестве goto.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...