2013-09-28 2 views
2

Рассмотрим C код из OpenCV Tutorial 8 - Chapter 9Переводя локальную статическую переменную в C в Common Lisp

// Learn the background statistics for one more frame 
void accumulateBackground(IplImage *I){ 
    static int first = 1; 
    cvCvtScale(I, Iscratch, 1, 0); 
    if(!first){ 
     cvAcc(Iscratch, IavgF); 
     cvAbsDiff(Iscratch, IprevF, Iscratch2); 
     cvAcc(Iscratch2, IdiffF); 
     Icount += 1.0; 
    } 
    first = 0; 
    cvCopy(Iscratch, IprevF); 
} 

Кажется, как код предназначен, что из-за

if(!first) 

программа никогда не будет выполнять:

cvAcc(Iscratch, IavgF); 
cvAbsDiff(Iscratch, IprevF, Iscratch2); 
cvAcc(Iscratch2, IdiffF); 
Icount += 1.0; 

В Lisp Я пытаюсь перевести это как:

(defun accumulate-background (i) 
    (setf 1st 1) 
    (cvt-scale i i-scratch-1 1 0) ;; To float 
    (if (not 1st) 
     (progn (acc i-scratch-1 i-avg-f) 
      (abs-diff i-scratch-1 i-prev-f i-scratch-2) 
      (acc i-scratch-2 i-diff-f) 
      (setf i-count (+ i-count 1.0)))) 
    (setf 1st 0) 
    (copy i-scratch-1 i-prev-f)) 

Для эквивалентной функции, с (not 1st) для !first, и я думаю, что это правильно. В C++ я:

static int first = 1; 

if(first){ 
    cout << "reached this part of code " << endl << " " << first << endl << endl; 
} 

но никогда не производит никакой продукции из-за дизайна кода, кажется. Почему дизайнеру учебного кода нравится это? Он копирует из Изучает OpenCV.

ответ

5

переменная first в коде C является static, что означает, что существует только один экземпляр этого, и что это общий между всеми вызовами функции.(См. Принятый ответ What does "static" mean? для получения дополнительной информации о static в C.) Это похоже на глобальную переменную, за исключением того, что другие функции не имеют к ней доступа (поскольку это не входит в их область действия). Вы можете имитировать это в Common Lisp, используя глобальную переменную, определенную с помощью defvar или defparameter, но я думаю, что более простой перевод сохранит ее локально для переведенной функции, обернув весь defun в let.

Во-первых, давайте посмотрим что-нибудь с аналогичное структура. Этот код делает что-то первого раза, но не на последующих вызовах:

(let ((firstp t)) 
    (defun frob (bar) 
    (when firstp 
     (print 'initialized) 
     (setf firstp nil)) 
    (print (list 'frobbed bar))) 
    nil) 

Теперь, когда мы бежим это время первого, firstp правда, так что мы увидим initialized на выходе , а на последующих запусках, мы не будем:

CL-USER> (frob 'bar3) 
INITIALIZED   ; printed output 
(FROBBED BAR3)   ; printed output 
;=> NIL 

CL-USER> (frob 'bar5) 
(FROBBED BAR5)   ; printed output 
;=> NIL 

код C, что у вас есть на самом деле делает что-то при каждом вызове кроме первым. Вы можете в качестве альтернативы рассказать об этом так: «если это не первый случай, сделайте что-нибудь». «Если» не предполагается, что он должен указывать на unless, который вы можете использовать для очистки своего кода. Наряду с let -wrapping- defun и надлежащего отступа мы имеем: [Что такое «статический» означает в программе C]

(let ((first t)) 
    (defun accumulate-background (i) 
    (cvt-scale i i-scratch-1 1 0) ;; To float 
    (unless first 
     (acc i-scratch-1 i-avg-f) 
     (abs-diff i-scratch-1 i-prev-f i-scratch-2) 
     (acc i-scratch-2 i-diff-f) 
     (setf i-count (+ i-count 1.0))) 
    (setf first nil) 
    (copy i-scratch-1 i-prev-f))) 
+0

Нет, '(setf first nil)' не может быть перемещен в блок 'except', потому что блок' except' никогда не будет выполнен. Кроме того, «это только нужно выполнить один раз» не является хорошей причиной для перемещения чего-либо в блок 'except', потому что этот блок предназначен для выполнения каждого вызова, кроме одного. –

+0

@ Rörd Да, я все испортил! Я попытался сохранить слишком много от первого примера, который я дал. Я удалил последний неправильный код и параграф. –

+0

@ Joshua Taylor спасибо Джошуа Тейлор и все ...... еще за то, что помогли мне с этим .... должен ли я включить свой рабочий код, если я его понял? –

1

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

Я думаю, что вам не хватает static int first = 1; Поскольку переменная сначала статическая (т. Е. Не сохраненная в стеке), она сохранит ее значение для вызовов функции. Поэтому сначала будет 0 (т. Е. Не первый) для всех вызовов после первого.

+0

Более подробную информацию о 'static' можно найти в (HTTP: // StackOverflow. com/q/572547/1281433) –

0

Это, вероятно, вопрос мнения, но мне не нравится оригинальный подход кода C. Я бы предпочел бы, если бы состояние функции зависело от аргументов, которые она получила тогда в каком-то глобально измененном состоянии.

Так, IMO, хороший способ переписать эту функцию (независимо от языка) было бы что-то вроде этого:

(defun accumulate-background (impl-image &key firstp) ...) 

или, если это возможно:

(defun accumulate-background (impl-image) 
    (labels ((%accumulate-background (firstp) ...)) 
    (%accumulate-background t))) 

Существует еще один способ избежать глобальных переменных:

(let (firstp) 
    (defun accumulate-background (impl-image) ...)) 

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

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

(defparameter *firstp* t) 
(defmacro with-first (&body body) 
    `(let (*firstp*) ,@body)) 
Смежные вопросы