将 duff 的设备从 C 移植到 JavaScript

Posted

技术标签:

【中文标题】将 duff 的设备从 C 移植到 JavaScript【英文标题】:Porting duff's device from C to JavaScript 【发布时间】:2016-08-29 04:14:55 【问题描述】:

我有这种 C 语言的 Duff 设备,它工作正常(将文本格式化为钱):

#include <stdio.h>
#include <string.h>

char *money(const char *src, char *dst)

    const char *p = src;
    char *q = dst;
    size_t len;

    len = strlen(src);
    switch (len % 3) 
        do 
            *q++ = ',';
            case 0: *q++ = *p++;
            case 2: *q++ = *p++;
            case 1: *q++ = *p++;
         while (*p);
    
    *q++ = 0;
    return dst;


int main(void)

    char str[] = "1234567890123";
    char res[32];

    printf("%s\n", money(str, res));
    return 0;

输出:

1,234,567,890,123

但我在尝试在 javascript 中实现相同的功能时遇到了问题:

function money(src, dst) 
    var len = src.length;
    var i = 0;

    switch (len % 3) 
        do 
            dst += ',';
            case 0: dst += src[i++];
            case 2: dst += src[i++];
            case 1: dst += src[i++];
         while (src[i]);
    
    return dst;


var str = "1234567890123";
var res = "";

console.log(money(str, res));

nodejs 返回此错误:

        do 
        ^^
SyntaxError: Unexpected token do

我的问题是:javascript 是否支持计算的 GOTO 语句?

P.D:我不想要替代品,我只想知道为什么不起作用。

相关问题:Does Duff's Device work in other languages?

【问题讨论】:

【参考方案1】:

我的问题是:javascript 是否支持计算的 GOTO 语句?

不是真的

P.D:我不想要替代品,我只想知道为什么不起作用。

它不起作用,因为在 JavaScript 中,switch statements must only contain case blocks。

虽然可能不会寻找解决方法,但其他人可能会在寻找解决方法时发现这个问题,所以无论如何我都会提供一个。 这要归功于mnieper,他在asm.js 上提出了建议。

基本思想是在顶层有一个while(true) 循环,在里面有一个switch 语句。

goto:
while(true)

    switch(where)
    
        // no breaks
        case 0:
            // some code...
        case 1:
            // some other code...
        // ...
    

为了模拟 goto,可以使用

where = 1;
continue goto;

不过,为了模拟 duff 的设备,只需将循环设为外部结构,并在 switch 语句中使用一个变量,该变量在第一次迭代后设置为将触发 switch 语句开始的值这是第一个案例。

所以在您的情况下,这意味着交换 switchdo...while() 并添加 default 情况和控制变量:

var where = len % 3;
do 
    switch (where) 
        default: dst += ',';
        case 0:  dst += src[i++];
        case 2:  dst += src[i++];
        case 1:  dst += src[i++];
    
    where = -1;
 while (src[i]);

一般来说,这种方法的一个巨大缺点当然是它不能跨回调工作,回调在 JavaScript 中几乎无处不在。 不过,只要在单个顺序上下文中使用它,它就可以工作。

有关详细信息,请参阅the ticket posted on the asm.js repo。

【讨论】:

对不起,我不明白:it will not work across callbacks,这是什么意思? @AlterMann 基本上它不会跨函数工作。在 JavaScript 中,传递函数对象作为对未来值或事件做出反应的一种方式是很常见的,例如等待 100 毫秒:window.setTimeout(function() /* */ , 100);。如果这样的函数在循环内declared,它可能会给人留下循环内run的印象(因此能够使用breakcontinue等),但如果异步执行则不是这样。只需谷歌“javascript return not working”,你就会发现很多新手问题都在问这个问题,只是用返回值代替。【参考方案2】:

JavaScript switch 语句不能这样工作。

switch (expr) 
  case expr:
    statements;
    break;
  case expr:
    statements;
    break;
  default:
    statements;
    break;

但 JavaScript 确实提供 labels 来控制你的循环

来自 MDN 的示例

var itemsPassed = 0;
var i, j;

top:
for (i = 0; i < items.length; i++)
  for (j = 0; j < tests.length; j++) 
    if (!tests[j].pass(items[i])) 
      continue top;
    
  

  itemsPassed++;

另一个来自 MDN 的例子

var allPass = true;
var i, j;

top:
for (i = 0; items.length; i++)
  for (j = 0; j < tests.length; i++)
    if (!tests[j].pass(items[i]))
      allPass = false;
      break top;
    

【讨论】:

以上是关于将 duff 的设备从 C 移植到 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp Duff的设备 - 在C中快速复制块

将 POSIX C 代码移植到 Windows

Duff的设备在Swift中

循环展开或 duff 可以帮助这种情况吗?

将 C 编译从 MinGW 移植到 VisualStudio(nmake)

冷知识:达夫设备(Duff's Device)效率真的很高吗?