在C和C++中,使用past-the-end指针来编写可以在任意大型数组上运行的函数通常很有用.C++提供了一个std::end重载,使这更容易.另一方面,在C中,我发现看到一个像这样定义和使用的宏并不罕见:
#define ARRAYLEN(array) (sizeof(array)/sizeof(array[0]))
// ...
int a [42];
do_something (a, a + ARRAYLEN (a));
Run Code Online (Sandbox Code Playgroud)
我还看到了一个指针算术技巧,用于让这些函数在单个对象上运行:
int b;
do_something (&b, &b + 1);
Run Code Online (Sandbox Code Playgroud)
我发现类似的事情可以用数组来完成,因为它们被C(并且我相信,C++)认为是"完整的对象".给定一个数组,我们可以在它之后立即派生一个指向数组的指针,取消引用该指针,并对结果对数组的引用使用数组到指针转换来获取原始数组的过去指针:
#define END(array) (*(&array + 1))
// ...
int a [42];
do_something (a, END (a));
Run Code Online (Sandbox Code Playgroud)
我的问题是:在解除引用指向不存在的数组对象的指针时,此代码是否显示未定义的行为?我对C和C++的最新版本对这段代码的评价感兴趣(不是因为我打算使用它,因为有更好的方法可以实现相同的结果,但因为它是一个有趣的问题).
我发现在我使用Common Lisp的有限经验中,有一些像这样的代码并不罕见
(setf (gethash key table)
(my-transformation (gethash key table)))
Run Code Online (Sandbox Code Playgroud)
从有setf能力的地方读取的地方,对存储在那里的值进行一些计算,然后写到同一个地方.我不喜欢的事情是这个地方将被计算两次,但这个地方(希望!)两次都是相同的.如果地点计算很昂贵,我们所做的工作量就是我们需要的两倍.
是否有可能消除双重计算的需要?也就是说,写一个宏是可能的(希望?)setf-inplace:
(setf-inplace (gethash key table) #'my-transformation)
Run Code Online (Sandbox Code Playgroud)
在概念上等效(忽略当前的multiple-values怪异)但可能比原始代码快得多,最好不依赖于实现细节?
我知道在这个特殊情况下我可能会把购物车放在马前面,因为SBCL会缓存查找gethash,但在我看来,其他setf有用的地方,例如(assoc key my-alist),可能不那么容易缓存 - 当然,通过setf-inplace上面的一些机制.