I'm trying to use D's equivalent of function pointer as a way of specifying optional functions as one field in a struct, of which I'm initializing an array of. This would be simple in C (aside from the messy syntax) but I'm stuck. This program:
struct Foo {
ubyte code;
bool yup;
void function(ubyte[] data, int size) special;
}
void boof(ubyte[] data, int size) {
/*do something*/
}
static immutable Foo[] markdefs = [
{0xF2, true, null},
{0xE4, true, boof},
{0xEE, false, null}
];
void main() {
}
gives me these errors:
funptr.d(17): Error: function funptr.boof (ubyte[] data, int size) is not
callable using argument types ()
funptr.d(17): Error: expected 2 function arguments, not 0
funptr.d(17): called from here: boof()
funptr.d(17): Error: cannot implicitly convert expression (boof()) of type
void to void function(ubyte[] data, int size)
I'm using dmd for D2 on a 64-bit Linux machine.
On line 17, your use of boof is a function call with no parameters (D allows the absence of parens). What you want is to take the reference of boof with the & operator.
Related
New to dart, take following code as example, //void function doesnt work and int/string function either returns null that is printed or value return which is automatically printed as can be seen in the output.
class Microphones{
String? name;
String? color;
int? model;
String printEverything(){
print(name);
return " ";
}
int? printint(){
print(model);
}
}
void main() {
var mic1=Microphones();
print(mic1.name);
mic1.name="Yeti";
mic1.color="black";
mic1.model=26;
print(mic1.name);
print(mic1.color);
print(mic1.model);
print(mic1.printEverything());
print(mic1.printint());
}
output:
null
Yeti
black
26
Yeti
26
null
i highly appreciate your replies/help in this regard.
All methods in Dart retuns null by default if you are not returning anything (either by having an empty return in methods specified to return void or not having any return at all in methods returning void or a nullable type like int?).
But return-type in the method signature specifies how the caller of the method should see the value. And here we have void which is described in the Dart language tour as:
A special type that indicates a value that’s never used.
https://dart.dev/guides/language/language-tour#a-basic-dart-program
So we specify void to signal to the user of our method, that the returned value should never be used. And the Dart analyzer and compiler will then try very hard to make sure you are not ending up using the returned value typed void.
Advanced section for the curious
But that does not mean it is impossible to use a returned value specified to be void by the method signature:
void someMethod() {
void someVoidVariable = 'Hey, I am a String!';
return someVoidVariable;
}
void someOtherMethod() => 'Hey, I am also a String!';
void main() {
print(someMethod() as String); // Hey, I am a String!
print(someOtherMethod() as String); // Hey, I am also a String!
}
In the first example, we force Dart to see our String as void. That is completely fine since all types can be seen as void. We are then allowed to return this void value since someMethod() is suppose to return void.
The reason for this forcing is that Dart would complain about (which makes sense because what we are doing is very much stupid and should never be in a real program):
void someMethod() {
return 'Hey, I am a String!';
// ERROR: A value of type 'String' can't be returned from the function
// 'someMethod' because it has a return type of 'void'.
}
Or this since we can't cast to void using as:
void someMethod() {
return 'Hey, I am a String!' as void; // ERROR: Expected a type name.
}
We are then casting that void back to a String to let Dart allow us to use the returned value in print() (since Dart otherwise would prevent us from trying to use the void typed value).
In the second example, I show the one of the reasons for why things are working like they does. In Dart, we can write these two method which are going to do the exact same (note I changed the return type to String for this example):
String someOtherMethod() {
return 'Hey, I am also a String!';
}
String someOtherMethod() => 'Hey, I am also a String!';
So the second way is a shorthand for if we just want to execute a single statement and return its value.
But what about:
void someOtherMethod() => 'Hey, I am also a String!';
If we followed the traditional rules, this would not be allowed since we cannot return a String since we have typed void. But sometimes, we also want to use this simple syntax to just execute a method and don't want to care about what that method would end up returning.
E.g. this:
final someList = <String>[];
void removeStringFromList(String string) => someList.remove(string);
Where the remove method on List is actually returning a bool which indicate if the element was inside the list.
So Dart ignores this problem when we use the => by just casting the result to void in this case. So in our last example, the returned bool is actually returned to the caller of removeStringFromList but because its type has been cast to void, the caller of removeStringFromList is prevented (in a lot of ways) from using the value.
I have the variable with the value "7438754876*567".I have got this from string as substring.I want to pass this value to c function.
void getRechargePinFromDestination(char* rechargeNumber)
{
setRechargeValue(rechargeNumber);
}
As I have declared as char, swift takes it as a Int8.How can I pass this value.Anyone please help me.Thanks in advance.
If the C function does not mutate the passed string then you should declare the argument as a const char*:
void getRechargePinFromDestination(const char* rechargeNumber)
{
// ...
}
Now you can pass Swift substrings by converting them to a String first (which is automatically converted to a temporary C string):
getRechargePinFromDestination(String(subString))
or with
subString.withCString { getRechargePinFromDestination($0) }
In either case, the C function is called with a pointer to a temporary C string representation, which is only valid during the function call.
While writing a Swift wrapper for a C wrapper of a C++ library, I've stumbled on some weird bugs regarding Swift's CVarArg. The C wrapper I already have uses variadic functions which I converted to functions using va_list as an argument so they could be imported (since Swift cannot import C variadic functions). When passing arguments to such a function, once bridged to Swift, it uses the private _cVarArgEncoding property of types conforming to CVarArg to "encode" the values which are then sent as a pointer to the C function. It seems however that this encoding is faulty for Swift Strings.
To demonstrate, I've created the following package:
Package.swift
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "CVarArgTest",
products: [
.executable(
name: "CVarArgTest",
targets: ["CVarArgTest"]),
],
targets: [
.target(
name: "CLib"),
.target(
name: "CVarArgTest",
dependencies: ["CLib"])
]
)
CLib
CTest.h
#ifndef CTest_h
#define CTest_h
#include <stdio.h>
/// Prints out the strings provided in args
/// #param num The number of strings in `args`
/// #param args A `va_list` of strings
void test_va_arg_str(int num, va_list args);
/// Prints out the integers provided in args
/// #param num The number of integers in `args`
/// #param args A `va_list` of integers
void test_va_arg_int(int num, va_list args);
/// Just prints the string
/// #param str The string
void test_str_print(const char * str);
#endif /* CTest_h */
CTest.c
#include "CTest.h"
#include <stdarg.h>
void test_va_arg_str(int num, va_list args)
{
printf("Printing %i strings...\n", num);
for (int i = 0; i < num; i++) {
const char * str = va_arg(args, const char *);
puts(str);
}
}
void test_va_arg_int(int num, va_list args)
{
printf("Printing %i integers...\n", num);
for (int i = 0; i < num; i++) {
int foo = va_arg(args, int);
printf("%i\n", foo);
}
}
void test_str_print(const char * str)
{
puts(str);
}
main.swift
import Foundation
import CLib
// The literal String is perfectly bridged to the CChar pointer expected by the function
test_str_print("Hello, World!")
// Prints the integers as expected
let argsInt: [CVarArg] = [123, 456, 789]
withVaList(argsInt) { listPtr in
test_va_arg_int(Int32(argsInt.count), listPtr)
}
// ERROR: Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
let argsStr: [CVarArg] = ["Test", "Testing", "The test"]
withVaList(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
The package is available here as well.
As commented in the code above, printing a String via C or a va_list containing Ints works as expected, but when converted to const char *, there's an exception (EXC_BAD_ACCESS (code=EXC_I386_GPFLT)).
So, in short: did I mess up the C side of it or is Swift doing something wrong here? I've tested this in Xcode 11.5 and 12.0b2. If it's a bug, I'll be happy to report it.
This one's a bit tricky: your string is actually being bridged to an Objective-C NSString * rather than a C char *:
(lldb) p str
(const char *) $0 = 0x3cbe9f4c5d32b745 ""
(lldb) p (id)str
(NSTaggedPointerString *) $1 = 0x3cbe9f4c5d32b745 #"Test"
(If you're wondering why it's an NSTaggedPointerString rather than just an NSString, this article is a great read -- in short, the string is short enough to be stored directly in the bytes of the pointer variable rather than in an object on the heap.
Looking at the source code for withVaList, we see that a type's va_list representation is determined by its implementation of the _cVarArgEncoding property of the CVarArg protocol. The standard library has some implementations of this protocol for some basic integer and pointer types, but there's nothing for String here. So who's converting our string to an NSString?
Searching around the Swift repo on GitHub, we find that Foundation is the culprit:
//===----------------------------------------------------------------------===//
// CVarArg for bridged types
//===----------------------------------------------------------------------===//
extension CVarArg where Self: _ObjectiveCBridgeable {
/// Default implementation for bridgeable types.
public var _cVarArgEncoding: [Int] {
let object = self._bridgeToObjectiveC()
_autorelease(object)
return _encodeBitsAsWords(object)
}
}
In plain English: any object which can be bridged to Objective-C is encoded as a vararg by converting to an Objective-C object and encoding a pointer to that object. C varargs are not type-safe, so your test_va_arg_str just assumes it's a char* and passes it to puts, which crashes.
So is this a bug? I don't think so -- I suppose this behavior is probably intentional for compatibility with functions like NSLog that are more commonly used with Objective-C objects than C ones. However, it's certainly a surprising pitfall, and it's probably one of the reasons why Swift doesn't like to let you call C variadic functions.
You'll want to work around this by manually converting your strings to C-strings. This can get a bit ugly if you have an array of strings that you want to convert without making unnecessary copies, but here's a function that should be able to do it.
extension Collection where Element == String {
/// Converts an array of strings to an array of C strings, without copying.
func withCStrings<R>(_ body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
return try withCStrings(head: [], body: body)
}
// Recursively call withCString on each of the strings.
private func withCStrings<R>(head: [UnsafePointer<CChar>],
body: ([UnsafePointer<CChar>]) throws -> R) rethrows -> R {
if let next = self.first {
// Get a C string, add it to the result array, and recurse on the remainder of the collection
return try next.withCString { cString in
var head = head
head.append(cString)
return try dropFirst().withCStrings(head: head, body: body)
}
} else {
// Base case: no more strings; call the body closure with the array we've built
return try body(head)
}
}
}
func withVaListOfCStrings<R>(_ args: [String], body: (CVaListPointer) -> R) -> R {
return args.withCStrings { cStrings in
withVaList(cStrings, body)
}
}
let argsStr: [String] = ["Test", "Testing", "The test"]
withVaListOfCStrings(argsStr) { listPtr in
test_va_arg_str(Int32(argsStr.count), listPtr)
}
// Output:
// Printing 3 strings...
// Test
// Testing
// The test
I've tried to use the Freeglut library in a Swift 4 Project. When the
void glutInit(int *argcp, char **argv);
function is shifted to Swift, its declaration is
func glutInit(_ pargc: UnsafeMutablePointer<Int32>!, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!)
Since I don't need the real arguments from the command line I want to make up the two arguments. I tried to define **argv in the Bridging-Header.h file
#include <OpenGL/gl.h>
#include <GL/glut.h>
char ** argv[1] = {"t"};
and use them in main.swift
func main() {
var argcp: Int32 = 1
glutInit(&argcp, argv!) // EXC_BAD_ACCESS
glutInitDisplayMode(UInt32(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH));
glutCreateWindow("my project")
glutDisplayFunc(display)
initOpenGL()
glutMainLoop()
but with that I get Thread 1: EXC_BAD_ACCESS (code=1, address=0x74) at the line with glutInit().
How can I initialize glut properly? How can I get an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>! so that it works?
The reason the right code in C char * argv[1] = {"t"}; does not work is because Swift imports fixed size C-array as a tuple, not a pointer to the first element.
But your char ** argv[1] = {"t"}; is completely wrong. Each Element of argv needs to be char **, but you assign char * ("t"). Xcode must have shown you a warning at first build:
warning: incompatible pointer types initializing 'char **' with an expression of type 'char [2]'
You should better take incompatible pointer types warning as error, unless you know what you are doing completely.
Generally, you should better not write some codes generating actual code/data like char * argv[1] = {"t"}; in a header file.
You can try it with Swift code.
As you know, when you want to pass a pointer to single element T, you declare a var of type T and pass &varName to the function you call.
As argcp in your code.
As well, when you want to pass a pointer to multiple element T, you declare a var of type [T] (Array<T>) and pass &arrName to the function you call.
(Ignoring immutable case to simplify.)
The parameter argv matches this case, where T == UnsafeMutablePointer<Int8>?.
So declare a var of type [UnsafeMutablePointer<Int8>?].
func main() {
var argc: Int32 = 1
var argv: [UnsafeMutablePointer<Int8>?] = [
strdup("t")
]
defer { argv.forEach{free($0)} }
glutInit(&argc, &argv)
//...
}
But I wonder if you really want to pass something to glutInit().
You can try something like this:
func main() {
var argc: Int32 = 0 //<- 0
glutInit(&argc, nil)
//...
}
I'm not sure if freeglut accept this, but you can find some articles on the web saying that this works in some implementation of Glut.
I have a C api that looks as follows
struct foo_private_t;
typedef foo_private_t* foo_t;
void foo_func(void**x);
Where the API is intended to be used like this
foo_t x;
void foo_func((void**) &x);
Why the API takes a void** and not a foo_t* is beyond the scope of this question. The problem is when I try to call this API from swift. First I import the C header into swift via the bridging header. Then I try to invoke foo_func with a pointer to a swift object.
var x:foo_t?
foo_func(&x)
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'
That error is expected, I need a pointer to the pointer, so I tried.
withUnsafeMutablePointer(to: x){ x_p in foo_func(x_p) }
// error is cannot convert value of type 'UnsafeMutablePointer<_>' to expected argument type 'UnsafeMutablePointer<UnsafeMutableRawPointer?>!'
This also seems reasonable as x_p is similar to &x, a single level of pointerness. The next attempt I would have expected to work.
withUnsafeMutablePointer(to: x){ x_p in foo_func(&x_p) }
// error is cannot pass immutable value of type 'UnsafeMutableRawPointer?' as inout argument
Searching around for this error reveals that if I was calling a swift function I should use the inout modifier to a parameter. But since I am calling a C api I am not sure that I can make such a modification. How can I pass a pointer that is a mutable value?
If the intention is to pass the address of x to the C function
in a way that foo_func() can assign a new value to x (which
is what the C code
foo_t x;
void foo_func((void**) &x);
does) then it would be:
var x: foo_t?
withUnsafeMutablePointer(to: &x) {
$0.withMemoryRebound(to: UnsafeMutableRawPointer?.self, capacity: 1) {
foo_func($0)
}
}
Inside withUnsafeMutablePointer(), $0 is a
UnsafeMutablePointer<foo_t?>
and this is rebound to a pointer of the expected type
UnsafeMutablePointer<UnsafeMutableRawPointer?>
I was able to get this to work.
var e = UnsafeMutableRawPointer(x)
foo_func(&e)
x is already a pointer, so it can be converted to a raw pointer. Then I need a pointer to that raw pointer, so I take the address of e. I guess I need the e variable because an implicit temporary value cannot be passed as an argument to an inout parameter. E.g.
foo_func(&UnsafeMutableRawPointer(x))
// error is cannot convert value of type 'foo_t?' (aka 'Optional<OpaquePointer>') to expected argument type 'UnsafeMutableRawPointer?'