I am writing a program that has an array which size I know, it is a fixed instruction set. Each entry in the array maps to an struct of the opcode and some metadata, such as the function that implements the opcode and its name, a String.
I need to allocate the array before I actually compute and fill the instruction set on each opcode.
Rust won't let me allocate such array statically, even if I know the size and when the initialized state does NOT require ANY pointers, as I would like all strings to be empty, which means no allocations and you could have a "zero value" of the string that is preferably fine to be copied.
Any suggestions? Is there anyway to do it?
Seems Rust really likes to you use a Vec for everything? Even when static memory, which should be preferable on a non GC program language, would have been possible in many cases such as this? This is confusing.
From the rust reference:
If the length operand has a value greater than 1 then this requires that the type of the repeat operand is Copy or that it must be a path to a constant item.
Therefore, to initialize an array using [VALUE; NUM] syntax, either the type implements the Copy trait or that VALUE is a const.
As pointed out by Chayim Friedman, you can use code like below:
const EMPTY: Instruction = Instruction { name: String::new() };
static ARRAY: [Instruction; 5] = [EMPTY; 5];
However, if you are working with a fixed set of data, it might be easier to just populate the list with predefined names, using &'static str.
If there is a need to create an array from a value that cannot be made to a constant and is not Copy, you can use std::array::from_fn like so:
let value = String::new();
let array: [_; 6] = std::array::from_fn(|_| value.clone());
Related
I started learning C and wanted to try some of the Swift-C interoperability.
I have a small C function which reads me a file and concatenates some useful letters into a char* variable. After some testing, I cannot find a way to pass my obtained char* data back to swift. I have written a small dummy code to illustrate what I am trying to achieve.
var letters: [CChar] = []
functionWithArray(&letters)
print("Back in swift: \(letters)")
And the C function is:
void functionWithArray(char* letters) {
int arrayLenght = 5;
int testLenght = 10; // Expand array to this value (testing)
int currentArrayPosition = 0; //Keep track of the assigned values
letters = malloc(sizeof(char)*arrayLenght);
while (currentArrayPosition < testLenght) {
if (currentArrayPosition == arrayLenght) {
arrayLenght++;
letters = realloc(letters, sizeof(char)*arrayLenght);
}
letters[currentArrayPosition] = *"A";
++currentArrayPosition;
}
printf("End of C function: %s\n", letters);
}
I get this as an output:
End of C function: AAAAAAAAAA
Back in swift: []
Program ended with exit code: 0
As you can see, inside the C function I've got the desired result, but back in swift I could not find a way to obtain the modified array. I do not return letters directly with the function because I need to return more values from that function. I'm new to C so please be kind.
There are two main issues with your approach here — one in C and one in Swift:
In C, function parameters are passed by value, and are effectively mutable local variables. That means that when functionWithArray receives char *letters, letters is a local variable containing a pointer value to the buffer of letters in memory. Importantly, that means that letters is assignable, but not in the way that you think:
letters = malloc(sizeof(char)*arrayLenght);
allocates an entirely new buffer through malloc, and assigns the newly-created pointer value to your local letters variable. Before the assignment, letters is a pointer to the buffer you were getting from Swift; after, to an unrelated buffer in memory. These two buffers are completely unrelated to one another, and because letters is just a local variable, this assignment is not propagaged in any way outside of the function.
Note that this is just a rule of C: as you learn more C, you'll likely discover that in order to assign a variable from inside of a function to outside of a function, you need to wrap the variable in another layer of pointers and write through that pointer (e.g., you would need to receive char **letters and assign *letters = malloc(...) to have any effect on a variable being passed in — and the variable couldn't be passed in directly, but rather, its address would need to be passed in).
However, you can't generally make use of this fact because,
The implicit conversion of an Array<T> to an UnsafeMutablePointer<T> (e.g. [CChar] → UnsafeMutablePointer<CChar> in Swift == char * in C) does not allow you to assign an entirely new buffer to the array instance. You can write into the contents of the buffer by writing to pointer values, but you cannot allocate a new block of memory and reassign the contents of the array to that new block
Instead, you'll need to either:
Have functionWithArray return an entirely new array and length from C — you mention this isn't possible for functionWithArray specifically because of the other values it needs to return, but theoretically you can also create a C struct which wraps up all of the return values together and return one of those instead
Rewrite functionWithArray to receive an array and a length, and pre-reserve enough space in the array up-front to fill it appropriately:
var letters: [CChar] = []
letters.reserveCapacity(/* however much you need */)
functionWithArray(&letters, letters.capacity)
In functionWithArray, don't reassign letters, but instead fill it up to the capacity given to you with results. Of course, this will only work if you know in Swift ahead of time how much space functionWithArray will need, which you might not
Alternatively, you can also use Array.init(unsafeUninitializedCapacity:initializingWith:) to combine these operations by having Array preallocate some space, and you can pass in the inout UnsafeMutableBufferPointer<CChar> to C where you can allocate memory if you need to and assign to the buffer pointer, then write out to the inout Int how many array elements you allocated and initialized. This does also require a capacity, though, and is a more complicated solution
Of these two approaches, if functionWithArray really does need to dynamically reallocate memory and grow the buffer, then (1) is likely going to be easier.
I'm currently writing a project in C, and I need to be able to fill a 2D array with information already stored in another 2D array. In a separate C file, I have this array:
int levelOne[][4] =
{{5,88,128,0},
{153,65,0,0},
{0,144,160,20}}; //First Array
int levelTwo[][4] =
{{5,88,128,0},
{153,65,0,0},
{0,144,160,20}}; //Second Array
And in my main file, I have this variable which I'd like to fill with the information from both of these arrays at different points in my code. (This isn't exactly what I'm doing, but it's the general gist):
#include "arrayFile.c"
void main()
{
int arrayContainer[][4] = levelOne;
while (true)
{
func(arrayContainer);
if(foo)
{
arrayContainer = levelTwo;//Switches to the other array if the conditional is met.
}
}
}
I know this method doesn't work - you can't overwrite items in arrays after they're instantiated. But is there any way to do something like this? I know I'll most likely need to use pointers to do this instead of completely overwriting the array, however there's not a lot of information on the internet about pointers with multidimensional arrays. In this situation, what's best practice?
Also, I don't know exactly how many arrays of 4 there will be, so I wouldn't be able to use a standard 3D array and just switch between indexes, unless there's a way to make a 3D jagged array that I don't know about.
Given the definitions you show, such as they are, all you need is memcpy(arrayContainer, levelTwo, sizeof LevelTwo);.
You should ensure that arrayContainer has sufficient memory to contain the copied data and that LevelTwo, since it is used as the operand of sizeof, is a designator for the actual array, not a pointer. If it is not, replace sizeof LevelTwo with the size of the array.
If you do not need the actual memory filled with data but simply need a way to refer to the contents of the different arrays, make arrayContainer a pointer instead of an array, as with int (*arrayContainer)[4];. Then you can use arrayContainer = levelOne; or arrayContainer = levelTwo; to change which data it points to.
Also, I don't know exactly how many arrays of 4 there will be, so I wouldn't be able to use a standard 3D array and just switch between indexes, unless there's a way to make a 3D jagged array that I don't know about.
It is entirely possible to have a pointer to dynamically allocated memory which is filled with pointers to arrays of four int, and those pointers can be changed at will.
I am attempting to return a dynamically declared array from a function; thus far I am returning a structure to hold a pointer to the memory block that malloc() assigned for the array AND an integer to store the length of the array.
This made me wonder; How does the C Compiler(or whatever) handle an automatic array declared in a program?
eg.
main()
{
//delcare an array holding 3 elements
int array[] = {1,2,3};
/*variable to hold length of array
*size of array / size of 1st element in the array == length of the array
*this will == 3
*/
int array_Length = (sizeof(array))/(sizeof(*array));
//call malloc for a block of memory to hold 3 integers(worth of memory)
int* ptr = malloc(3*(sizeof(int)));
/*not exactly sure what this formula means when using a pointer???
*but it seems to always == 1
*/
int dynamic_array_length = (sizeof(ptr))/(sizeof(*ptr));
return 0;
}
My point is, the sizeof() operator somehow knows that the automatically declared array has 3 integers within it.
Or more generally:
sizeof(array)
where array is (N x type_size)
N is the number of elements within the array
type_size is the number of bytes of memory used to store the data type
Are automatic arrays stored with additional information about their size/length?
Are dynamic arrays stored differently? (I know that we control when a dynamic variable is freed from memory)
Operator sizeof is a compile-time construct (with the exception of VLA arguments). It tells you the object size in bytes because it knows the exact compile-time object type. And when you know the exact type the size is also immediately known. There's no need to separately store the number of elements anywhere.
Your declaration
int array[] = {1,2,3};
is equivalent to
int array[3] = {1,2,3};
meaning that array has type int[3]. So your sizeof(array) is interpreted as sizeof(int[3]), which is immediately known to the compiler.
sizeof does not know and does not care about any "dynamic arrays" of yours. All it cares about is that in sizeof(ptr) operator sizeof is applied to a pointer. So it evaluates to pointer size.
sizeof(...) is not a function call. It doesn't actually execute at runtime - that value is replaced at the compile time, so what's actually compiled is:
int array_length = 3;
The calculation of dynamic_array_length is incorrect. You divide the size of a pointer by the size of int. Which in your case happens to be the same and get 1 as a result.
Your dynamic array is stored differently - the pointer (on the stack) is separate from the data (on the heap). The first array is just data on the stack - the memory address is constant (for that stack frame) and gets used where needed.
Disregarding VLAs, the array size of an automatic array is a fact completely known at compile time, and is actually a part of the type of the variable. sizeof is a query (resolved at compile time) to the type system, which is a thing that exists only in the compiler internal data structures while it is compiling. The result is the actual variable size, which is treated essentially as if it was directly written in the source code.
Things about sizeof has been discussed enough, and we know it is a compile-time action.
But in fact, It is true that there is something about size is stored and used in run-time for dynamic variables. Otherwise the free can not do its work correctly.
Here is a good reference: how-do-malloc-and-free-work
You are hitting one of the inconsistencies of C. An array is just a pointer, except where it has been declared. The result of sizeof (somearray) is different, depending upon whether or not sizeof is used in the function defining somearray. In, C, as soon as you move away from the definition, there is no knowledge of anything other than the type of object in the array. That is just one of the many reasons why C programming is so error prone.
Most programming languages other than C or those derived from C, maintain an array descriptor that includes the number of dimensions, the number of elements, and, in some cases, the array bounds.
In the case of dynamic arrays, the library adds overhead, usually before, to the memory returned (sometimes additional overhead is added at the end). This is used so that library can know how much memory is freed.
1st Question:
Are D array function parameters always passed by reference, or by value?
Also, does the language implements Copy on Write for arrays?
E.g.:
void foo(int[] arr)
{
// is arr a local copy or a ref to an external array?
arr[0] = 42; // How about now?
}
2nd Question:
Suppose I have a large array that will be passed to function foo as a read-only parameter and it should be avoided as much as possible copying the array, since it is assumed to be a very large object. Which from the following (or none of them) would be the best declaration for function foo:
void foo(const int[] bigArray)
void foo(in int[] bigArray)
void foo(const ref int[] bigArray)
Technically, a dynamic array like int[] is just a pointer and a length. Only the pointer and length get copied onto the stack, not the array contents. An arr[0] = 42; does modify the original array.
On the other side, a static array like int[30] is a plain old data type consisting of 30 consecutive ints in memory. So, a function like void foo(int[30] arr) would copy 120 bytes onto the stack for a start. In such a case, arr[0] = 42; modifies the local copy of the array.
According to the above, each of the ways you listed avoids copying the array contents. So, whether you need the parameter to be const, in, const ref or otherwise depends on what you are trying to achieve besides avoiding array copy. For example, if you pass a ref int [] arr parameter, not only you can modify its contents, but also you will be able to modify the pointer and length (for example, create a wholly new array and assign it to arr so that it is visible from outside the function).
For further information, please refer to the corresponding articles on the DLang site covering arrays and array slices.
I am trying to interface with a Windows dll using Go. The dll function I want to use accepts a pointer to a byte array. Therefore I need to give it that byte array.
I am using the syscall libary to call the dll, as demonstrated here. My basic requirements are:
I am given the required size for the byte array
I create the byte array
I must get a pointer to the byte array
I then pass the pointer to the Windows dll
I can't figure out how to create a byte array in go, and get a pointer to it. This is obviously an unsafe operation, and the unsafe library can be helpful, but I need to create a dynamic-length byte array in the first place. Creating a slice with "make" doesn't help me, unless I can get a pointer to the slice's backing array.
Has anyone else encountered this or have any ideas?
I think syscall.ComputerName implementation https://golang.org/src/syscall/syscall_windows.go#395 would be a good example. It uses uint16s, not bytes, but otherwise ...
In your case it would be ptr := &myslice[0].
Alex
Well I found one gross solution. Apparently the structure of a slice contains a pointer to the backing byte array, the length of the backing byte array, and then the capacity of the backing byte array.
I am only interested in a pointer to the byte array, so I only need the first member of the slice's internal data.
Go's unsafe.Pointer will not cast a slice to an unsafe pointer, but it will cast a pointer to a slice as an unsafe pointer. Since I can cast an unsafe pointer to any old type of pointer I want, I can cast it to a pointer-to-a-pointer, which recovers the first member of the slice's internal data.
Here's a working example. I wanted a uintptr but you could cast it to any pointer type.
package main
import (
"fmt"
"unsafe"
)
func main() {
// Arbitrary size
n := 4
// Create a slice of the correct size
m := make([]int, n)
// Use convoluted indirection to cast the first few bytes of the slice
// to an unsafe uintptr
mPtr := *(*uintptr)(unsafe.Pointer(&m))
// Check it worked
m[0] = 987
// (we have to recast the uintptr to a *int to examine it)
fmt.Println(m[0], *(*int)(unsafe.Pointer(mPtr)))
}
If you wanted a *int instead, you could do mPtr := *(**int)(unsafe.Pointer(&m))
This works as long as a slice maintains this internal data structure. I am definitely open to a more robust solution that doesn't depend on the structure of Go's internals.