// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:ffi'; import 'package:ffi/ffi.dart'; main() { print('start main'); { // Basic operation: allocate, get, set, and free. Pointer p = calloc(); p.value = 42; int pValue = p.value; print('${p.runtimeType} value: ${pValue}'); calloc.free(p); } { // Undefined behavior before set. Pointer p = calloc(); int pValue = p.value; print('If not set, returns garbage: ${pValue}'); calloc.free(p); } { // Pointers can be created from an address. Pointer pHelper = calloc(); pHelper.value = 1337; int address = pHelper.address; print('Address: ${address}'); Pointer p = Pointer.fromAddress(address); print('${p.runtimeType} value: ${p.value}'); calloc.free(pHelper); } { // Address is zeroed out after free. Pointer p = calloc(); calloc.free(p); print('After free, address is zero: ${p.address}'); } { // Allocating too much throws an exception. try { int maxMint = 9223372036854775807; // 2^63 - 1 calloc(maxMint); } on Error { print('Expected exception on allocating too much'); } try { int maxInt1_8 = 1152921504606846975; // 2^60 -1 calloc(maxInt1_8); } on Error { print('Expected exception on allocating too much'); } } { // Pointers can be cast into another type, // resulting in the corresponding bits read. Pointer p1 = calloc(); p1.value = 9223372036854775807; // 2^63 - 1 Pointer p2 = p1.cast(); print('${p2.runtimeType} value: ${p2.value}'); // -1 Pointer p3 = p2.elementAt(1); print('${p3.runtimeType} value: ${p3.value}'); // 2^31 - 1 calloc.free(p1); } { // Data can be tightly packed in memory. Pointer p = calloc(8); for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { p.elementAt(i).value = i * 3; } for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { print('p.elementAt($i) value: ${p.elementAt(i).value}'); } calloc.free(p); } { // Values that don't fit are truncated. Pointer p11 = calloc(); p11.value = 9223372036854775807; print(p11); calloc.free(p11); } { // Doubles. Pointer p = calloc(); p.value = 3.14159265359; print('${p.runtimeType} value: ${p.value}'); p.value = 3.14; print('${p.runtimeType} value: ${p.value}'); calloc.free(p); } { // Floats. Pointer p = calloc(); p.value = 3.14159265359; print('${p.runtimeType} value: ${p.value}'); p.value = 3.14; print('${p.runtimeType} value: ${p.value}'); calloc.free(p); } { // IntPtr varies in size based on whether the platform is 32 or 64 bit. // Addresses of pointers fit in this size. Pointer p = calloc(); int p14addr = p.address; p.value = p14addr; int pValue = p.value; print('${p.runtimeType} value: ${pValue}'); calloc.free(p); } { // Void pointers are unsized. // The size of the element it is pointing to is undefined, // they cannot be allocated, read, or written. Pointer p1 = calloc(); Pointer p2 = p1.cast(); print('${p2.runtimeType} address: ${p2.address}'); calloc.free(p1); } { // Pointer to a pointer to something. Pointer pHelper = calloc(); pHelper.value = 17; Pointer> p = calloc(); // Storing into a pointer pointer automatically unboxes. p.value = pHelper; // Reading from a pointer pointer automatically boxes. Pointer pHelper2 = p.value; print('${pHelper2.runtimeType} value: ${pHelper2.value}'); int pValue = p.value.value; print('${p.runtimeType} value\'s value: ${pValue}'); calloc.free(p); calloc.free(pHelper); } { // The pointer to pointer types must match up. Pointer pHelper = calloc(); pHelper.value = 123; Pointer> p = calloc(); // Trying to store `pHelper` into `p.val` would result in a type mismatch. calloc.free(pHelper); calloc.free(p); } { // `nullptr` points to address 0 in c++. Pointer> pointerToPointer = calloc(); Pointer value = nullptr; pointerToPointer.value = value; value = pointerToPointer.value; print("Loading a pointer to the 0 address is null: ${value}"); calloc.free(pointerToPointer); } { // The toplevel function sizeOf returns element size in bytes. print('sizeOf(): ${sizeOf()}'); print('sizeOf(): ${sizeOf()}'); print('sizeOf(): ${sizeOf()}'); } { // With IntPtr pointers, one could manually setup arbitrary data // structures in C memory. // // However, it is advised to use Pointer> for that. void createChain(Pointer head, int length, int value) { if (length == 0) { head.value = value; return; } Pointer next = calloc(); head.value = next.address; createChain(next, length - 1, value); } int getChainValue(Pointer head, int length) { if (length == 0) { return head.value; } Pointer next = Pointer.fromAddress(head.value); return getChainValue(next, length - 1); } void freeChain(Pointer head, int length) { Pointer next = Pointer.fromAddress(head.value); calloc.free(head); if (length == 0) { return; } freeChain(next, length - 1); } int length = 10; Pointer head = calloc(); createChain(head, length, 512); int tailValue = getChainValue(head, length); print('tailValue: ${tailValue}'); freeChain(head, length); } print("end main"); }