def test_opaque_integer_as_function_result():
#import platform
#if platform.machine().startswith('sparc'):
# py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
#elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
# py.test.skip('Segfaults on mips64el')
# XXX bad abuse of "struct { ...; }". It only works a bit by chance
# anyway. XXX think about something better :-(
ffi = FFI()
ffi.cdef("""
typedef struct { ...; } myhandle_t;
myhandle_t foo(void);
""")
lib = ffi.verify("""
typedef short myhandle_t;
myhandle_t foo(void) { return 42; }
""")
h = lib.foo()
assert ffi.sizeof(h) == ffi.sizeof("short")
python类h()的实例源码
def test_take_and_return_partial_structs():
ffi = FFI()
ffi.cdef("""
typedef struct { int x; ...; } foo_t;
foo_t foo(foo_t, foo_t);
""")
lib = ffi.verify("""
typedef struct { int y, x; } foo_t;
foo_t foo(foo_t a, foo_t b) {
foo_t r = { 100, a.x * 5 + b.x * 7 };
return r;
}
""")
args = ffi.new("foo_t[3]")
args[0].x = 1000
args[2].x = -498
h = lib.foo(args[0], args[2])
assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
assert h.x == 1000 * 5 - 498 * 7
def test_FILE_stored_explicitly():
ffi = FFI()
ffi.cdef("int myprintf11(const char *, int); FILE *myfile;")
lib = ffi.verify("""
#include <stdio.h>
FILE *myfile;
int myprintf11(const char *out, int value) {
return fprintf(myfile, out, value);
}
""")
import os
fdr, fdw = os.pipe()
fw1 = os.fdopen(fdw, 'wb', 256)
lib.myfile = ffi.cast("FILE *", fw1)
#
fw1.write(b"X")
r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
fw1.close()
assert r == len("hello, 42!\n")
#
result = os.read(fdr, 256)
os.close(fdr)
# the 'X' might remain in the user-level buffer of 'fw1' and
# end up showing up after the 'hello, 42!\n'
assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
def test_ptr_to_opaque():
ffi = FFI()
ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
lib = ffi.verify("""
#include <stdlib.h>
typedef struct { int x; } foo_t;
int f1(foo_t* p) {
int x = p->x;
free(p);
return x;
}
foo_t *f2(int x) {
foo_t *p = malloc(sizeof(foo_t));
p->x = x;
return p;
}
""")
p = lib.f2(42)
x = lib.f1(p)
assert x == 42
def test_unicode_libraries():
try:
unicode
except NameError:
py.test.skip("for python 2.x")
#
import math
lib_m = "m"
if sys.platform == 'win32':
#there is a small chance this fails on Mingw via environ $CC
import distutils.ccompiler
if distutils.ccompiler.get_default_compiler() == 'msvc':
lib_m = 'msvcrt'
ffi = FFI()
ffi.cdef(unicode("float sin(double); double cos(double);"))
lib = verify(ffi, 'test_math_sin_unicode', unicode('#include <math.h>'),
libraries=[unicode(lib_m)])
assert lib.cos(1.43) == math.cos(1.43)
def test_opaque_integer_as_function_result():
#import platform
#if platform.machine().startswith('sparc'):
# py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
#elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
# py.test.skip('Segfaults on mips64el')
# XXX bad abuse of "struct { ...; }". It only works a bit by chance
# anyway. XXX think about something better :-(
ffi = FFI()
ffi.cdef("""
typedef struct { ...; } myhandle_t;
myhandle_t foo(void);
""")
lib = ffi.verify("""
typedef short myhandle_t;
myhandle_t foo(void) { return 42; }
""")
h = lib.foo()
assert ffi.sizeof(h) == ffi.sizeof("short")
def test_take_and_return_partial_structs():
ffi = FFI()
ffi.cdef("""
typedef struct { int x; ...; } foo_t;
foo_t foo(foo_t, foo_t);
""")
lib = ffi.verify("""
typedef struct { int y, x; } foo_t;
foo_t foo(foo_t a, foo_t b) {
foo_t r = { 100, a.x * 5 + b.x * 7 };
return r;
}
""")
args = ffi.new("foo_t[3]")
args[0].x = 1000
args[2].x = -498
h = lib.foo(args[0], args[2])
assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
assert h.x == 1000 * 5 - 498 * 7
def test_FILE_stored_explicitly():
ffi = FFI()
ffi.cdef("int myprintf11(const char *, int); FILE *myfile;")
lib = ffi.verify("""
#include <stdio.h>
FILE *myfile;
int myprintf11(const char *out, int value) {
return fprintf(myfile, out, value);
}
""")
import os
fdr, fdw = os.pipe()
fw1 = os.fdopen(fdw, 'wb', 256)
lib.myfile = ffi.cast("FILE *", fw1)
#
fw1.write(b"X")
r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
fw1.close()
assert r == len("hello, 42!\n")
#
result = os.read(fdr, 256)
os.close(fdr)
# the 'X' might remain in the user-level buffer of 'fw1' and
# end up showing up after the 'hello, 42!\n'
assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
def test_ptr_to_opaque():
ffi = FFI()
ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
lib = ffi.verify("""
#include <stdlib.h>
typedef struct { int x; } foo_t;
int f1(foo_t* p) {
int x = p->x;
free(p);
return x;
}
foo_t *f2(int x) {
foo_t *p = malloc(sizeof(foo_t));
p->x = x;
return p;
}
""")
p = lib.f2(42)
x = lib.f1(p)
assert x == 42
def test_errno_working_even_with_pypys_jit():
ffi = FFI()
ffi.cdef("int f(int);")
lib = ffi.verify("""
#include <errno.h>
int f(int x) { return (errno = errno + x); }
""")
@_run_in_multiple_threads
def test1():
ffi.errno = 0
for i in range(10000):
e = lib.f(1)
assert e == i + 1
assert ffi.errno == e
for i in range(10000):
ffi.errno = i
e = lib.f(42)
assert e == i + 42
def test_extension_object(self):
ffi = FFI()
ffi.cdef("double sin(double x);")
csrc = '/*7%s*/' % self + '''
#include <math.h>
#ifndef TEST_EXTENSION_OBJECT
# error "define_macros missing"
#endif
'''
lib = ffi.verify(csrc, define_macros=[('TEST_EXTENSION_OBJECT', '1')],
force_generic_engine=self.generic,
libraries=[self.lib_m])
assert lib.sin(12.3) == math.sin(12.3)
v = ffi.verifier
ext = v.get_extension()
assert 'distutils.extension.Extension' in str(ext.__class__) or \
'setuptools.extension.Extension' in str(ext.__class__)
assert ext.sources == [maybe_relative_path(v.sourcefilename)]
assert ext.name == v.get_module_name()
assert ext.define_macros == [('TEST_EXTENSION_OBJECT', '1')]
def test_simple_case():
ffi = FFI()
ffi.cdef("double sin(double x);")
lib = ffi.verify('#include <math.h>', libraries=lib_m)
assert lib.sin(1.23) == math.sin(1.23)
def test_Wconversion_floating():
lib = _Wconversion("float sin(double);",
"#include <math.h>", libraries=lib_m)
res = lib.sin(1.23)
assert res != math.sin(1.23) # not exact, because of double->float
assert abs(res - math.sin(1.23)) < 1E-5
def test_Wconversion_float2int():
_Wconversion("int sinf(float);",
"#include <math.h>", libraries=lib_m)
def test_Wconversion_double2int():
_Wconversion("int sin(double);",
"#include <math.h>", libraries=lib_m)
def test_rounding_1():
ffi = FFI()
ffi.cdef("double sinf(float x);")
lib = ffi.verify('#include <math.h>', libraries=lib_m)
res = lib.sinf(1.23)
assert res != math.sin(1.23) # not exact, because of double->float
assert abs(res - math.sin(1.23)) < 1E-5
def test_strlen_exact():
ffi = FFI()
ffi.cdef("size_t strlen(const char *s);")
lib = ffi.verify("#include <string.h>")
assert lib.strlen(b"hi there!") == 9
def test_strlen_approximate():
lib = _Wconversion("int strlen(char *s);",
"#include <string.h>")
assert lib.strlen(b"hi there!") == 9
def test_strlen_array_of_char():
ffi = FFI()
ffi.cdef("size_t strlen(char[]);")
lib = ffi.verify("#include <string.h>")
assert lib.strlen(b"hello") == 5
def test_longdouble():
ffi = FFI()
ffi.cdef("long double sinl(long double x);")
lib = ffi.verify('#include <math.h>', libraries=lib_m)
for input in [1.23,
ffi.cast("double", 1.23),
ffi.cast("long double", 1.23)]:
x = lib.sinl(input)
assert repr(x).startswith("<cdata 'long double'")
assert (float(x) - math.sin(1.23)) < 1E-10
def test_funcptr_as_argument():
ffi = FFI()
ffi.cdef("""
void qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *, const void *));
""")
ffi.verify("#include <stdlib.h>")
def test_array_as_argument():
ffi = FFI()
ffi.cdef("""
size_t strlen(char string[]);
""")
ffi.verify("#include <string.h>")
def test_function_typedef():
ffi = FFI()
ffi.cdef("""
typedef double func_t(double);
func_t sin;
""")
lib = ffi.verify('#include <math.h>', libraries=lib_m)
assert lib.sin(1.23) == math.sin(1.23)
def test_return_partial_struct():
ffi = FFI()
ffi.cdef("""
typedef struct { int x; ...; } foo_t;
foo_t foo(void);
""")
lib = ffi.verify("""
typedef struct { int y, x; } foo_t;
foo_t foo(void) { foo_t r = { 45, 81 }; return r; }
""")
h = lib.foo()
assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
assert h.x == 81
def test_FILE_stored_in_stdout():
if not sys.platform.startswith('linux'):
py.test.skip("likely, we cannot assign to stdout")
ffi = FFI()
ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
lib = ffi.verify("""
#include <stdio.h>
FILE *setstdout(FILE *f) {
FILE *result = stdout;
stdout = f;
return result;
}
""")
import os
fdr, fdw = os.pipe()
fw1 = os.fdopen(fdw, 'wb', 256)
old_stdout = lib.setstdout(fw1)
try:
#
fw1.write(b"X")
r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42))
fw1.close()
assert r == len("hello, 42!\n")
#
finally:
lib.setstdout(old_stdout)
#
result = os.read(fdr, 256)
os.close(fdr)
# the 'X' might remain in the user-level buffer of 'fw1' and
# end up showing up after the 'hello, 42!\n'
assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
def test_string_to_voidp_arg():
ffi = FFI()
ffi.cdef("int myfunc(void *);")
lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }")
res = lib.myfunc(b"hi!")
assert res == ord(b"h")
p = ffi.new("char[]", b"gah")
res = lib.myfunc(p)
assert res == ord(b"g")
res = lib.myfunc(ffi.cast("void *", p))
assert res == ord(b"g")
res = lib.myfunc(ffi.cast("int *", p))
assert res == ord(b"g")
def test_implicit_unicode_on_windows():
from cffi import FFIError
if sys.platform != 'win32':
py.test.skip("win32-only test")
ffi = FFI()
e = py.test.raises(FFIError, ffi.cdef, "int foo(LPTSTR);")
assert str(e.value) == ("The Windows type 'LPTSTR' is only available after"
" you call ffi.set_unicode()")
for with_unicode in [True, False]:
ffi = FFI()
ffi.set_unicode(with_unicode)
ffi.cdef("""
DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename,
DWORD nSize);
""")
lib = ffi.verify("""
#include <windows.h>
""", libraries=['Kernel32'])
outbuf = ffi.new("TCHAR[]", 200)
n = lib.GetModuleFileName(ffi.NULL, outbuf, 500)
assert 0 < n < 500
for i in range(n):
#print repr(outbuf[i])
assert ord(outbuf[i]) != 0
assert ord(outbuf[n]) == 0
assert ord(outbuf[0]) < 128 # should be a letter, or '\'
def test_math_sin():
import math
ffi = FFI()
ffi.cdef("float sin(double); double cos(double);")
lib = verify(ffi, 'test_math_sin', '#include <math.h>')
assert lib.cos(1.43) == math.cos(1.43)
def test_math_sin_type():
ffi = FFI()
ffi.cdef("double sin(double);")
lib = verify(ffi, 'test_math_sin_type', '#include <math.h>')
# 'lib.sin' is typed as a <built-in method> object on lib
assert ffi.typeof(lib.sin).cname == "double(*)(double)"
# 'x' is another <built-in method> object on lib, made very indirectly
x = type(lib).__dir__.__get__(lib)
py.test.raises(TypeError, ffi.typeof, x)
#
# present on built-in functions on CPython; must be emulated on PyPy:
assert lib.sin.__name__ == 'sin'
assert lib.sin.__module__ == '_CFFI_test_math_sin_type'
assert lib.sin.__doc__ == 'direct call to the C function of the same name'
def test_defines__CFFI_():
# Check that we define the macro _CFFI_ automatically.
# It should be done before including Python.h, so that PyPy's Python.h
# can check for it.
ffi = FFI()
ffi.cdef("""
#define CORRECT 1
""")
lib = verify(ffi, "test_defines__CFFI_", """
#ifdef _CFFI_
# define CORRECT 1
#endif
""")
assert lib.CORRECT == 1