2012-01-09 37 views
2

我正在用C语言编写一个机器人,并且遇到了一个我似乎无法解决的问题。如何获取C中的字符串值?

解决此问题的唯一方法是使用大量goto语句。 我想找出一种方法来保存自己写超过100个goto点和语句,如果语句等,我想知道是否有一种方法来获得一个字符串的值。对于示例 -

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

有什么办法gotoNext值,或在Next的值代入goto声明?

如果有办法做到这一点,那么无论字符串Next的值是多少,我都可以为每个驱动命令更改Next的值,然后goto

换句话说,只是将字符串转换为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(这是多长的命令,以毫秒为单位),然后你让代码转到你输入的驾驶命令。驾驶命令驱动你放入的时间量,然后执行next命令;

这是否有一种方法,使goto语句“解释”的字符串作为一个标识符,它是可以改变一切理论上的工作。

大约有4个简单的方法,我能想到的,现在,可以让过去,这很容易,但它们会使代码真的很长,凌乱。

既然您对我的问题有更好的理解,那么还有其他意见吗? :)

顺便说一句 - 我正在使用一个名为robotC的程序,我正在编写一个vex机器人。所以我必须使用纯,基本,C,和我不能使用任何插件或任何东西......这是另一个原因,这是复杂的,因为我不能有多个类和类似的东西...

+4

有一定是更好的方法做你比100级的goto做什么... – Mysticial 2012-01-09 03:17:28

+1

什么实际问题? – 2012-01-09 03:18:24

+1

如果你能描述根本问题,有人可能会发现比这些'goto's更好的方法 – Kevin 2012-01-09 03:20:08

回答

1

你在想关于这个错误的方式。您需要调用的每个操作都应该是一个函数,然后您可以通过检查“下一个”变量来选择应该调用哪个函数。

这可能是一个字符串作为你所提到的,但你可能会使用一个枚举类型,以可读的,但更高效的代码是最好的。

另一种选择,虽然可能矫枉过正,将是确保你的函数都使用相同的参数和返回类型,然后用一个函数指针来跟踪代码段,下一步应该执行。

小提示:如果你认为你需要超过1个goto语句来实现你可能不看最好的解决方案一定的目标。

+1

我不认为你的建议替代是矫枉过正。如果他有100个功能,但没有办法统一他们的叫法,那么他可能只有100个if块。 – dreamlax 2012-01-09 03:27:22

4

作为C语言的扩展,GCC提供了一个名为computed gotos的功能,它允许您在运行时计算标签goto。但是,我强烈建议您重新考虑您的设计

而不是使用gotos超过一百个标签(这将容易导致不可维护的意大利面条代码),请考虑改为使用函数指针。代码将更加结构化和可维护。

4

而不是goto的,我会打电话100函数之一。而C也不会从字符串处理转换为你工作,这是很容易使用结构的有序数组:

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

然后做(例如)通过数组的二进制搜索来查找功能匹配一个字符串。

另请注意,许多实际系统都提供像GetProcAddress(Windows)或dlsym(Unix/Linux)的东西来为您处理一些工作。

1

您需要退一步并考虑你正在试图解决的问题的其他解决方案。其中一人可能是这样的:

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

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

void (*nextStep)(void) = NULL; 

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

See it in action

0

首先,让我与其他人同意前言本:这可能不是去了解你正在试图做正确的方式。特别是,我想你可能需要一个有限状态机器,并且我建议this article指导如何做到这一点。

这就是说。 。 。你可以通过使用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的原始规范示例。

+0

代替'goto HelperLabel',为什么不把switch语句放在一个循环中,而是使用'break'来代替? – dreamlax 2012-01-09 03:29:15

+0

@dreamlax:好主意;完成。我猜想我在考虑各种情况需要与其他控制结构(其中'goto'允许和'break''没有)交错 - 否则为什么OP首先需要'goto'? - 但由于没有明确规定,是的,最好的做法可能是从略干净的方法开始。 – ruakh 2012-01-09 03:35:34

+0

确切地说,它与其他控制结构交织在一起,这就是为什么我使用goto – user1137900 2012-01-11 02:57:45

0

怎么样switch?可以使用int/enum/whatever或者检查字符串的值(例如,循环它并且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
#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; 
}