类似于 C 语言里的指针问题: 如图, 一个变量存储着另一个变量的地址. 我如何去访问并修改 hello
这个值?
Emacs Lisp
学得不好, 不知道如何更好地描述这个问题, 请见谅.
类似于 C 语言里的指针问题: 如图, 一个变量存储着另一个变量的地址. 我如何去访问并修改 hello
这个值?
Emacs Lisp
学得不好, 不知道如何更好地描述这个问题, 请见谅.
a
指向 "hello"
,b
指向同一个"hello"
,所以修改 b
也就是修改 a
(let* ((a "hello")
(b a))
(aset b 0 ?H)
a)
;; => "Hello"
a
指向 "hello"
,b
的 car
指向同一个`“hello”
(let* ((a "hello")
(b (list a)))
;; 通过 b 修改 a
(aset (car b) 0 ?H)
a)
;; => "Hello"
看起来 Emacs Lisp 没有「指向指针的指针」。
(Emacs Lisp 字符串是可修改的,但是实际上一般把字符串当作常量而不修改它)
感谢耐心解答问题!
法一我的理解是, 变量 a
和变量 b
同时指向了同一个 hello
. 换句话说, 这两个变量完全是一回事, 因为都指向了同一个内存地址. 这个貌似与题不相符.
法二我暂时理解不了, mark 一下日后看.
我刚学 setf
这个函数, 我的想法是:
(let ((str '("h" "e" "l" "l" "o"))
(return-str ""))
(setf (car str) "H")
(dolist (el str)
(setq return-str (concat return-str el)))
return-str)
;; ===> "Hello"
ELISP> (setq a "hello")
"hello"
ELISP> (setq b 'a)
a
ELISP> (setf (symbol-value b) "world")
ELISP> a
"world"
但就允许用户的操作来说,这里面并没有一个变量保存了另一个变量的地址
Emacs Lisp 没法表示「指向一个指针的指针」,所以不会出现你图中的情形。
elisp 没有指针的概念,想操作指针,只能退回到 c 语言层面了,例如楼上几位提到的 aset/set(setf)。
如果一定要找出对应关系,也并非无迹可寻:
#+BEGIN_SRC emacs-lisp :results value
(let* ((a "hello")
(b 'a))
;; (setf (symbol-value b) "world")
;; 等于
;; (set b "world")
;; 等于
(set 'a "world")
;; (aset (symbol-value b) 0 ?W)
;; 等于
(aset a 0 ?W)
a)
#+END_SRC
#+RESULTS:
: World
#+BEGIN_SRC C :results output :includes <stdio.h> :flags -std=gnu99 -Wall -Werror
char a[10] = "hello\n";
char *p;
p = &a[0] // 相当于 (let (... (b 'a)) ...)
sprintf(p, "world\n"); // 相当于 (set b "world")
*p = 'W'; // 相当于 (aset (symbol-value b) 0 ?W)
// a[0] = 'W'; // 相当于 (aset a 0 ?W)
printf("%s\n", a);
#+END_SRC
#+RESULTS:
: World
可以把 symbol 看作指针:
| 操作 | elisp | C |
|------+---------------------------------+-------------|
| 寻址 | (symbol-value b) | *p |
| 取址 | 'a | &a |
| 下标 | (aset a 0 ?W) | a[0] = 'W' |
| | 或 (aset (symbol-value b) 0 ?W) | 或 *p = 'W' |
十分感谢回复!
今天我碰到了指针的需求(想在函数里面改变传参的原变量的值),查了一下,发现有个不错的解决方案:
(gv-ref)
相当于 C 的 &
,(gv-deref)
相当于 C 的 *
。
于是可以有以下操作:
(setq test 'test)
(defun test1 (a)
(setf (gv-deref a) nil))
(test1 (gv-ref test))
test
;; ===> nil