浏览代码

New conversion specifier '%p' for 'string.format'

The call 'string.format("%p", val)' gives a Lua equivalent to the
C API function 'lua_topointer'.
Roberto Ierusalimschy 6 年之前
父节点
当前提交
dfebe439db
共有 3 个文件被更改,包括 31 次插入3 次删除
  1. 5 0
      lstrlib.c
  2. 10 3
      manual/manual.of
  3. 16 0
      testes/strings.lua

+ 5 - 0
lstrlib.c

@@ -1185,6 +1185,11 @@ static int str_format (lua_State *L) {
           nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
           nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
           break;
           break;
         }
         }
+        case 'p': {
+          const void *p = lua_topointer(L, arg);
+          nb = l_sprintf(buff, MAX_ITEM, form, p);
+          break;
+        }
         case 'q': {
         case 'q': {
           if (form[2] != '\0')  /* modifiers? */
           if (form[2] != '\0')  /* modifiers? */
             return luaL_error(L, "specifier '%%q' cannot have modifiers");
             return luaL_error(L, "specifier '%%q' cannot have modifiers");

+ 10 - 3
manual/manual.of

@@ -6751,8 +6751,7 @@ Returns a formatted version of its variable number of arguments
 following the description given in its first argument (which must be a string).
 following the description given in its first argument (which must be a string).
 The format string follows the same rules as the @ANSI{sprintf}.
 The format string follows the same rules as the @ANSI{sprintf}.
 The only differences are that the conversion specifiers and modifiers
 The only differences are that the conversion specifiers and modifiers
-@T{*}, @id{h}, @id{L}, @id{l}, @id{n},
-and @id{p} are not supported
+@T{*}, @id{h}, @id{L}, @id{l}, and @id{n} are not supported
 and that there is an extra specifier, @id{q}.
 and that there is an extra specifier, @id{q}.
 
 
 The specifier @id{q} formats booleans, nil, numbers, and strings
 The specifier @id{q} formats booleans, nil, numbers, and strings
@@ -6791,6 +6790,14 @@ it is converted to one following the same rules of @Lid{tostring}.
 If the specifier has any modifier,
 If the specifier has any modifier,
 the corresponding string argument should not contain @x{embedded zeros}.
 the corresponding string argument should not contain @x{embedded zeros}.
 
 
+The specifier @id{p} formats the pointer
+returned by @Lid{lua_topointer}.
+That gives a unique string identifier for tables, userdata,
+threads, strings, and functions.
+For other values (numbers, nil, booleans),
+this specifier results in a string representing
+the pointer @id{NULL}.
+
 }
 }
 
 
 @LibEntry{string.gmatch (s, pattern [, init])|
 @LibEntry{string.gmatch (s, pattern [, init])|
@@ -8768,7 +8775,7 @@ address space.)
 }
 }
 
 
 @item{
 @item{
-The constant @Lid{LUA_ERRGCMM} was removed.
+The constant @id{LUA_ERRGCMM} was removed.
 Errors in finalizers are never propagated;
 Errors in finalizers are never propagated;
 instead, they generate a warning.
 instead, they generate a warning.
 }
 }

+ 16 - 0
testes/strings.lua

@@ -153,6 +153,22 @@ else   -- compatible coercion
   assert(tostring(-1203 + 0.0) == "-1203")
   assert(tostring(-1203 + 0.0) == "-1203")
 end
 end
 
 
+do  -- tests for '%p' format
+  -- not much to test, as C does not specify what '%p' does.
+  -- ("The value of the pointer is converted to a sequence of printing
+  -- characters, in an implementation-defined manner.")
+  local null = string.format("%p", nil)
+  assert(string.format("%p", {}) ~= null)
+  assert(string.format("%p", 4) == null)
+  assert(string.format("%p", print) ~= null)
+  assert(string.format("%p", coroutine.running()) ~= null)
+  assert(string.format("%p", {}) ~= string.format("%p", {}))
+  assert(string.format("%p", string.rep("a", 10)) ==
+         string.format("%p", string.rep("a", 10)))     -- short strings
+  assert(string.format("%p", string.rep("a", 300)) ~=
+         string.format("%p", string.rep("a", 300)))     -- long strings
+  assert(#string.format("%90p", {}) == 90)
+end
 
 
 x = '"ílo"\n\\'
 x = '"ílo"\n\\'
 assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
 assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')