A library I am using has a very weird API that often takes string pointers. Currently I am doing this:
s := "foobar"
weirdFun(&s)
to pass strings. Is there a way to do this without the variable?
Maybe you should inform the author of the library, that the strings in Go are already references (to a structure, which is internally represented as a slice of runes), so no expensive copy operation is made by passing string to a function, it's call by reference.
Hope this helps!
The address operation &x can be used with addressable values.
According to the language specification:
The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
So, you can work around this using a composite literal:
package main
import (
"fmt"
)
func main() {
s := "text"
fmt.Printf("value: %v, type: %T\n", &s, &s)
fmt.Printf("value: %v, type: %T\n", &[]string{"literal"}[0], &[]string{"literal"}[0])
}
Even though it's possible I don't recommend using this. This is not an example of clear code.
The Azure SDK uses string pointers to distinguish between no value and the empty string.
Use Azure's StringPtr function to create a pointer to a string literal.
import (
⋮
"github.com/Azure/go-autorest/autorest/to"
)
⋮
res, err := someClient.Create(ctx, someService.ExampleParameters{
Location: to.StringPtr(location),
})
The library is really weird, but
you can do this in one line with function wrap, for example
func PointerTo[T ~string](s T) *T {
return &s
}
s := "string"
weirdFun(PointerTo(s))
Related
We have some structure S. Is it possible to make a converter so that the expression
s := S(a_string)
began to compile, where a_string is actually a string.
The allowed conversions are listed in Spec: Conversions. There's a section for "Conversions to and from a string type". Only those are allowed, you can't "extend" or change the behavior of conversions.
You may however always write a function that takes a string and returns a value of type S.
func Parse(s string) S {
var r S
// Parsing logic
return r
}
Using it is / looks like the same as a conversion:
s := Parse(a_string)
In Golang, everything is passed by value. If I pass an array "directly" (as opposed as passing it by pointer), then any modification made in the function will be found outside of it
func f(a []int) {
a[0] = 10
}
func main() {
a := []int{2,3,4}
f(a)
fmt.Println(a)
}
Output: [10 3 4]
This is because, to my understanding, an array constitutes (among other things) of a pointer to the underlying data array.
Unless I am mistaken (see here) strings also constitute (along with a "len" object) of a pointer (a unsafe.Pointer) to the underlying data. Hence, I was expecting the same behaviour as above but, apparently, I was wrong.
func f(s string) {
s = "bar"
}
func main() {
s := "foo"
f(s)
fmt.Println(s)
}
Output: "foo"
What is happening here with the string? Seems like the underlying data is being copied when the string is passed as argument.
Related question: When we do not wish our function to modify the string, is it still recommended to pass large strings by pointer for performance reasons?
A string has two values in it: pointer to an array, and the string length. When you pass string as an argument, those two values are copied, not the underlying array.
There is no way to modify the contents of string other than using unsafe. When you pass a *string to a function and that function modifies the string, the function simply modifies the string to point to a different array.
I come from a C# background where System.String is immutable and string concatenation is relatively expensive (as it requires reallocating the string) we know to use the StringBuilder type instead as it preallocates a larger buffer where single characters (Char, a 16-bit value-type) and short strings can be concatenated cheaply without extra allocation.
I'm porting some C# code to Swift which reads from a bit-array ([Bool]) at sub-octet indexes with character lengths less than 8 bits (it's a very space-conscious file format).
My C# code does something like this:
StringBuilder sb = new StringBuilder( expectedCharacterCount );
int idxInBits = 0;
Boolean[] bits = ...;
for(int i = 0; i < someLength; i++) {
Char c = ReadNextCharacter( ref idxInBits, 6 ); // each character is 6 bits in this example
sb.Append( c );
}
In Swift, I assume NSMutableString is the equivalent of .NET's StringBuilder, and I found this QA about appending individual characters ( How to append a character to string in Swift? ) so in Swift I have this:
var buffer: NSMutableString
for i in 0..<charCount {
let charValue: Character = readNextCharacter( ... )
buffer.AppendWithFormat("%c", charValue)
}
return String(buffer)
But I don't know why it goes through a format-string first, that seems inefficient (reparsing the format-string on every iteration) and as my code is running on iOS devices I want to be very conservative with my program's CPU and memory usage.
As I was writing this, I learned my code should really be using UnicodeScalar instead of Character, problem is NSMutableString does not let you append a UnicodeScalar value, you have to use Swift's own mutable String type, so now my code looks like:
var buffer: String
for i in 0..<charCount {
let x: UnicodeScalar = readNextCharacter( ... )
buffer.append(x)
}
return buffer
I thought that String was immutable, but I noticed its append method returns Void.
I still feel uncomfortable doing this because I don't know how Swift's String type is implemented internally, and I don't see how I can preallocate a large buffer to avoid reallocations (assuming Swift's String uses a growing algorithm).
(This answer was written based on documentation and source code valid for Swift 2 and 3: possibly needs updates and amendments once Swift 4 arrives)
Since Swift is now open-source, we can actually have a look at the source code for Swift:s native String
swift/stdlib/public/core/String.swift
From the source above, we have following comment
/// Growth and Capacity
/// ===================
///
/// When a string's contiguous storage fills up, new storage must be
/// allocated and characters must be moved to the new storage.
/// `String` uses an exponential growth strategy that makes `append` a
/// constant time operation *when amortized over many invocations*.
Given the above, you shouldn't need to worry about the performance of appending characters in Swift (be it via append(_: Character), append(_: UniodeScalar) or appendContentsOf(_: String)), as reallocation of the contiguous storage for a certain String instance should not be very frequent w.r.t. number of single characters needed to be appended for this re-allocation to occur.
Also note that NSMutableString is not "purely native" Swift, but belong to the family of bridged Obj-C classes (accessible via Foundation).
A note to your comment
"I thought that String was immutable, but I noticed its append method returns Void."
String is just a (value) type, that may be used by mutable as well as immutable properties
var foo = "foo" // mutable
let bar = "bar" // immutable
/* (both the above inferred to be of type 'String') */
The mutating void-return instance methods append(_: Character) and append(_: UniodeScalar) are accessible to mutable as well as immutable String instances, but naturally using them with the latter will yield a compile time error
let chars : [Character] = ["b","a","r"]
foo.append(chars[0]) // "foob"
bar.append(chars[0]) // error: cannot use mutating member on immutable value ...
I'm struggling to call mktemp in D:
import core.sys.posix.stdlib;
import std.string: toStringz;
auto name = "alpha";
auto tmp = mktemp(name.toStringz);
but I can't figure out how to use it so DMD complains:
/home/per/Work/justd/fs.d(1042): Error: function core.sys.posix.stdlib.mktemp (char*) is not callable using argument types (immutable(char)*)
How do I create a mutable zero-terminated C-style string?
I think I've read somewhere that string literals (const or immutable) are implicitly convertible to zero (null)-terminated strings.
For this specific problem:
This is because mktemp needs to write to the string. From mktemp(3):
The last six characters of template must be XXXXXX and these are replaced with a string that makes the filename unique. Since it will be modified, template must not be a string constant, but should be declared as a character array.
So what you want to do here is use a char[] instead of a string. I'd go with:
import std.stdio;
void main() {
import core.sys.posix.stdlib;
// we'll use a little mutable buffer defined right here
char[255] tempBuffer;
string name = "alphaXXXXXX"; // last six X's are required by mktemp
tempBuffer[0 .. name.length] = name[]; // copy the name into the mutable buffer
tempBuffer[name.length] = 0; // make sure it is zero terminated yourself
auto tmp = mktemp(tempBuffer.ptr);
import std.conv;
writeln(to!string(tmp));
}
In general, creating a mutable string can be done in one of two ways: one is to .dup something, or the other is to use a stack buffer like I did above.
toStringz doesn't care if the input data is mutable, it always returns immutable (apparently...). But it is easy to do it yourself:
auto c_str = ("foo".dup ~ "\0").ptr;
That's how you do it, .dup makes a mutable copy, and appending the zero terminator yourself ensures it is there.
string name = "alphaXXXXXX"; // last six X's are required by mktemp
auto tmp = mktemp((name.dup ~ "\0").ptr);
In addition to Adam's great answer, there's also std.utf.toUTFz, in which case you can do
void main()
{
import core.sys.posix.stdlib;
import std.conv, std.stdio, std.utf;
auto name = toUTFz!(char*)("alphaXXXXXX");
auto tmp = mktemp(name);
writeln(to!string(tmp));
}
std.utf.toUTFz is std.string.toStringz's more capable cousin as it will generate null-terminated UTF-8, UTF-16, and UTF-32 strings (as opposed to just UTF-8) as well as any level of constness. The downside is that it's more verbose for cases where you just want immutable(char)*, because you have to specify the return type.
However, if efficiency is a concern, Adam's solution is likely better simply because it avoids having to allocate the C-string that you pass to mktemp on the heap. toUTFz is shorter though, so if you don't care about the efficiency cost of allocating the C-string on the heap (and most programs probably won't), then toUTFz is arguably better. It depends on the requirements of your particular program.
I want to use LabVIEW's Call Library Function Node to access a DLL function, and have this function return a string to displayed on my VI. How would I go about doing this? I am quite happy returning numbers from my DLL, but am really struggling to find any examples of how to return a string.
There are at least a few ways to return a string from a Call Library Function Node:
Return a C string pointer from your DLL function, and configure the Call Library Function Node to have a return type of "C String Pointer". Note that the returned string must be valid after the function returns, so it can't be a pointer to a string allocated on the stack. It must be one of the following: allocated on the heap, statically allocated, a constant string literal, etc.
It looks like examples/dll/regexpr/Regular Expression Solution/VIs/Get Error String.vi in the LabVIEW directory takes this approach.
Allocate a string in your VI, pass it to the Call Library Function Node using a "C String Pointer" parameter as Azim suggested, and overwrite its contents in the DLL. One way to allocate the string is to use Initialize Array to create a u8 array of the desired size, and then use Byte Array To String to convert it to a string.
Be sure that the string you pass in is large enough to hold the contents of your string, and make sure to pass the string length to the DLL so that it knows how large the buffer is. I believe that the default parameter is an empty string. Figuring out the right string length may require calling into the DLL twice, if your VI's first guess isn't large enough.
Pass the string to the Call Library Function Node using a "String Handle" parameter, and use LabVIEW functions in your DLL to resize the string as necessary. This requires your DLL to be specifically designed to interface with LabVIEW and requires linking against a static library that is provided with LabVIEW.
An example of this method ships with LabVIEW as examples/dll/hostname/hostname.vi.
I assume from your question that you already have a DLL that can return numbers to Labview. To return a string from the DLL, I have created a DLL with the following C++ function
void returnString(char myString[])
{
const char *aString = "test string";
memcpy(myString, aString, 12);
}
In Labview I then use the Call Library Function Node and configure it as follows
Library Name or Path: c:\path\to\my\custom.dll
Function Name: returnString
Calling Convention: C
Parameters:
Parameter: return type
type: void
Parameter: arg1
type: String
string format: C String Pointer
Function prototype:
void returnString(CStr arg1);
After connect the arg1 output in the block diagram to a string indicator and run. The string "test string" should appear in the front panel.
I tried to have the returnString function be of type CStr as in
CStr returnString()
{ ...
}
but I got build errors when compiling the DLL project.
Update
Thanks to #bk1e comment don't forget to pre-allocate space in Labview for the string.