2009-05-14 12 views
9

En MATLAB, ¿cómo se puede saber en qué parte del código se está obteniendo una variable?¿Cómo determinar de dónde se está imprimiendo un número en MATLAB?

Tengo alrededor de 10K líneas de código MATLAB con aproximadamente 4 personas trabajando en ello. En algún lugar, alguien se ha deshecho de una variable en una secuencia de comandos de MATLAB en la forma típica:

foo 

Por desgracia, no sé lo que está recibiendo la variable de salida. Y la salida está abarrotando otras salidas más importantes.

¿Alguna idea?

p.s. ¿Alguno vez intentas sobrescribir Standard.out? Dado que la integración de MATLAB y Java es tan estrecha, ¿funcionaría? Un truco que he usado en Java cuando me enfrento con este problema es reemplazar Standard.out con mi propia versión.

+0

oh, odio eso. Desearía que fuera posible tener una configuración global en MATLAB para arrojar un error siempre que encuentre enunciados sin punto y coma. –

+0

Terminó siendo un disp (str2num (FOO)); enterrado profundamente en el código. El truco fue darse cuenta de que la salida era la misma todo el tiempo, buscando a través de todos los 200Gig de archivos de datos y encontrando ese valor. Averiguar qué variable interna tenía ese valor, y luego rastrear cada referencia en el código con ese valor. Demasiadas líneas de código, con demasiados errores de pelusa para usar los enfoques propuestos. ¡¡¡¡GRACIAS!!!! – John

+0

Sí, pero mi truco de sobrecargar disp podría haber funcionado rápidamente. –

Respuesta

7

Ooh, odio esto también. Desearía que Matlab tuviera una "pantalla dbstop if" para detenerse exactamente en esto.

El mlint travelling de weiyin es una buena idea. Sin embargo, Mlint no puede ver el código dinámico, como los argumentos a eval() o las devoluciones de llamada con identificador de cadena. He corrido para generar resultados como este en callbacks como este, donde update_table() devuelve algo en algunas condiciones.

uicontrol('Style','pushbutton', 'Callback','update_table') 

Puede "pato golpear" un método en los tipos incorporados para darle un gancho para dbstop. En un directorio en su ruta Matlab, cree un nuevo directorio llamado "@double", y haga un archivo @ double/display.m como este.

function display(varargin) 
builtin('display', varargin{:}); 

A continuación, puede hacer

dbstop in double/display at 2 

y ejecutar su código. Ahora se le colocará en el depurador cada vez que se invoque implícitamente la visualización mediante el punto y coma omitido, incluido el código dinámico. Al hacerlo para @double, parece que también cubre las char y las celdas. Si se muestra un tipo diferente, es posible que deba experimentar.

Probablemente pueda anular el disp() incorporado de la misma manera. Creo que esto sería análogo a un reemplazo personalizado para la transmisión System.out de Java.

No hace falta decir que la adición de métodos a los tipos incorporados no es estándar, no es compatible, es muy propensa a errores y algo de lo que hay que tener cuidado fuera de una sesión de depuración.

3

Si usted tiene una línea como:

foo = 2 

y no hay ";" en el extremo, a continuación, la salida se vuelca en la pantalla con el nombre de la variable que aparece en primer lugar:

foo = 

    2 

En este caso, se debe buscar el archivo de la cadena "foo =" y encontrar la línea de la falta de un " ; ".

Si está viendo una salida sin que aparezca el nombre de la variable, entonces la salida probablemente se está volcando a la pantalla usando la función DISP o FPRINTF. Buscar en el archivo "disp" o "fprintf" debería ayudarlo a encontrar dónde se muestran los datos.

Si está viendo una salida con el nombre de variable "ans", este es un caso cuando se realiza un cálculo, no se coloca en una variable y falta un ';' al final de la línea, como por ejemplo:

size(foo) 

En general, esta es una mala práctica para la visualización de lo que está sucediendo en el código, ya que (como usted ha descubierto) que puede ser difícil de encontrar en estos se han colocado en una gran pieza de código. En este caso, la forma más fácil de encontrar la línea ofensiva es usar MLINT, como han sugerido otras respuestas.

5

Este es un patrón típico que mLint le ayudará a encontrar:

alt text

lo tanto, buscar en el lado derecho del editor de las líneas de color naranja. Esto lo ayudará a encontrar no solo esta optimización, sino muchas, muchas más. Observe también que su nombre de variable está resaltado.

+0

+1: MLINT funciona bien para un ';' perdido, pero supongo que no ayudaría si el DISP fuera el problema. – gnovice

0

Tendrá que recorrer todos sus archivos m (probablemente utilizando una función recursiva o unix ('find -type f -iname * .m')). Llamar a mlint en cada nombre de archivo:

r = mlint(filename); 

r será una estructura (posiblemente vacía) con un campo de mensaje. Busque el mensaje que comienza con "Terminar declaración con punto y coma para suprimir la salida".

1

Puede ejecutar mlint como una función e interpretar los resultados.

>> I = mlint('filename','-struct'); 
>> isErrorMessage = arrayfun(@(S)strcmp(S.message,... 
     'Terminate statement with semicolon to suppress output (in functions).'),I); 
>>I(isErrorMessage).line 

Esto solo encontrará los puntos y comas faltantes en ese único archivo. Entonces esto debería ejecutarse en una lista de archivos (funciones) a los que se llama desde alguna función principal.

Si desea encontrar llamadas a disp() o fprintf(), necesitará leer en el texto del archivo y usar expresiones regulares para encontrar las llamadas.

Nota: Si utiliza una secuencia de comandos en lugar de una función, deberá cambiar el mensaje anterior para que diga: 'Terminar declaración con punto y coma para suprimir la salida (en las secuencias de comandos)'.

3

Me gusta la idea de "dbstop if display", sin embargo, esta no es una opción dbstop que yo sepa.

Si todo lo demás falla, todavía hay esperanza. Mlint es una buena idea, pero si hay muchos miles de líneas y muchas funciones, entonces es posible que nunca encuentre al delincuente. Peor aún, si este código ha sido escrito de manera descuidada, aparecerán tropecientos millones de indicadores de mlint. ¿Cómo lo limitarás?

Una solución es mostrar su camino hacia allí. Sobrecargaría la función de visualización. Solo temporalmente, pero esto funcionará. Si la salida es objeto de dumping a la línea de comandos como

ans = 
     stuff 

o como

foo = 
     stuff 

A continuación, se ha escrito con pantalla. Si sale como

stuff 

entonces disp es el culpable. ¿Por qué eso importa? Sobrecargar al ofensor.Cree un nuevo directorio en algún directorio que se encuentre en la parte superior de su ruta de búsqueda de MATLAB, llamado @double (suponiendo que el resultado sea una variable doble. Si es un carácter, necesitará un directorio @char) NO coloque el @ doble directorio en la ruta de búsqueda de MATLAB, simplemente colóquelo en algún directorio que esté en su ruta.

Dentro de este directorio, poner un nuevo archivo-m llamado disp.m o display.m, dependiendo de su determinación de lo que ha hecho la salida de línea de comandos. El contenido del archivo-m será una llamada a la función interna, lo que le permitirá a continuación, llamar a la versión incorporada de disp o muestre en la entrada.

Ahora, establecer un punto de depuración dentro de la nueva función. Cada vez que se genera salida en la pantalla, se llamará a esta función. Si hay varios eventos, es posible que deba utilizar el depurador para permitir que continúe el procesamiento hasta que el delincuente quede atrapado. Eventualmente, este proceso atrapará la línea ofensiva. Recuerde, usted está en el depurador! Utilizar el depurador para determinar qué función llamada disp, y dónde. Puede salir de disp o display, o simplemente mirar los contenidos de dbstack para ver qué ha sucedido.

Cuando todo está hecho y reparar el problema, elimine este directorio extra, y la función DISP/pantalla se pone en ella.

1

La sobrecarga de Andrew Janke es una sugerencia muy útil la única otra cosa es que en lugar de utilizar dbstop me parece que lo siguiente funciona mejor, por la simple razón de que detener la visualización hace que la ejecución pare, cada vez que aparece .m se llama, incluso si no se escribe nada.

De esta manera, la parada sólo se activa cuando la pantalla está llamado a escribir una cadena no nula, y no tendrá que pasar por una potencialmente muy gran número de llamadas pantalla inútil

function display(varargin) 
builtin('display', varargin{:}); 
if isempty(varargin{1})==0 
keyboard 
end 
1

Un Una forma infalible de localizar tales cosas es recorrer paso a paso el código en el depurador observando el resultado. Esto procedería de la siguiente manera:

  1. Agregue un punto de interrupción en la primera línea del script/función de más alto nivel que produce la salida no deseada. Ejecutar la función/script.
  2. pasar por encima de las líneas (no pisar) hasta que vea la salida no deseada.
  3. Cuando encuentre la línea/función que produce la salida, ya sea solucionarlo, si es en este archivo, o abrir la subfunción/script que está produciendo la salida. Elimine el punto de ruptura de la función de nivel superior y coloque un punto de interrupción en la primera línea de la función de nivel inferior. Repita desde el paso 1 hasta que la línea producir la salida se encuentra.

Aunque un dolor, se encuentra la línea relativamente rápido de esta manera a menos que tenga funciones enormes/scripts, que es una mala práctica de todos modos. Si los guiones son así, podría utilizar una especie de enfoque de partición para ubicar la línea en la función de manera similar. Esto implicaría poner un punto de quiebre en el inicio, a continuación, la mitad camino a través y tomando nota de los cuales la mitad de la función produce la salida, a continuación, reducir a la mitad otra vez y así sucesivamente hasta que la línea se encuentra.

1

he tenido este problema con el código mucho más pequeña y es un tío, por lo que a pesar de que el PO encontró su solución, voy a publicar un pequeño truco que aprendí.

1) En la línea de comandos de Matlab, active el 'más'.

more on 

2) Cambiar el tamaño de la parte prompt-y/terminal-y de la ventana a una línea de texto en altura.

3) Ejecute el código. Se detendrá donde sea que necesite imprimir, ya que no hay espacio para imprimirlo (más está bloqueando en una [espacio] o [abajo] presiona).

4) Presione [ctrl] - [C] para matar su programa en el lugar donde no podría imprimir.

5) Regrese su área pronta-y al tamaño normal. Comenzando en la parte superior de la traza, haga clic en los bits que se pueden hacer clic en el texto rojo. Estos son tus posibles culpables. (Por supuesto, es posible que tenga que haber presionado [abajo], etc., para pasar partes donde el código estaba realmente destinado a imprimir cosas).

Cuestiones relacionadas