If I compile a file with this definition in SBCL:
(print "Give me a number")
(setq *x* (read))
(defun check(*x*)
(if (= *x* 5) (setq *x* 10) (format t "~d is not 5" *x*))
)
There are two warnings:
warning: undefined variable: *X*
This is located at the global setq, because setq does not declare global variables. So the compiler does not know any global variable named *x*.
Then, inside the function:
style-warning:
using the lexical binding of the symbol (*X*), not the
dynamic binding, even though the name follows
the usual naming convention (names like *FOO*) for special variables
--> PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA
==>
#'(SB-INT:NAMED-LAMBDA AAAB::CHECK
(*X*)
(DECLARE (SB-C::TOP-LEVEL-FORM))
(BLOCK CHECK
(IF (= *X* 5)
(SETQ *X* 10)
(FORMAT T "~d is not 5" *X*))))
This is pretty self-explanatory, but here the binding is lexical.
This is however not a property of defun, this is because there is no declared special variable named *x*.
If instead, you use defvar or defparameter, there is no warning (e.g. (defvar *x* 0)). The same goes if you only declare the variable as special: (declaim (special *x*)), before you define the function that binds it.
Inside the function, assuming *x* is declared as a special variable, the bindings works as a let, which means you can use special variables as function parameters. In your case this does not change much because you only set the current binding with the inner setq (the parameter shadows the global binding), so in effect this is a lot like a lexical variable.
But you can use a special variable to rebind dynamically a parameter:
(defun foo (*a*) ...)
This is the same as:
(defun foo (a)
(let ((*a* a))
...))