Arrays can be passed as pointer to a function or even as reference. Passing it as reference gives an alias on which sizeof and count operators will also work. This makes pass by reference look superior.
However, pass by pointer seems to be the norm in books. Why? Is there something I particularly need to know about pass by reference for arrays?
Passing by reference means that your function can only accept fixed-size arrays (that's why it knows their size, because the compiler enforces it). Passing by pointer means otherwise. Also, passing by pointer lets you pass nullptr, for better or worse.
I usually use std::vector and like to pass by const reference. That said, if my api may at some point be called by c code, using pass by const pointer may make sense, though you then have to also want to send down the size. If the function may be called with an std::array or a std::vector, you could decide to send down a pointer (and size), or a set of iterators (begin/end).
If we are talking about using std::array, the template argument requires the size of the array. This would mean in a normal function, you'd need a fixed size:
void myfunc( const std::array<int, 5>& mydata ){...}
However, if we do a templated function, templating on size, that is no longer a problem.
template<unsigned int SZ>
void myfunc(const std::array<int, SZ>& mydata) {...}
If we are talking about stack allocated c-style arrays... Good C++ style is to prefer std::array/std::vector to c-style arrays. I would recommend reading C++ Coding Standard by Herb Sutter chapter 77 on page 152 speaks about the subject. When using c-style arrays, sending down the pointer and size is the standard way to go.
Related
I am presently in a case where I need to call a lot of function pointers that has been extracted at runtime. The problem is that the arguments are unknown at compilation time.
But, at runtime I receive datas that allows me to know the arguments of the function and I can even store the arguments in a char* array. The problem is that I don't have a function pointer model to cast it into.
In high level language, I know there is function like "InvokeMethode(String name,Byte[] args)" that interpret the bytes array like arguments. Since reflection does not exist in C, I have no hope to see this with a function pointer.
One solution that I have in mind (and it's really bad), is to create a model of function pointer at compilation time that will cast in a "hardcoded way" the ptr to the right type to use like this:
void callFunc64Bits(void* funcPtr,long long args);
void callFuncVoid(void* funcPtr);
The problem is that I will have to create like 100 function like this that will cast the pointer correctly.
Is there a way to do it more efficiently?
Thank you very much!
This is a hard problem without, unfortunately, good or easy answers.
See this former SO question: Run-time parameters in gcc (inverse va_args/varargs)
See this C FAQ question: http://c-faq.com/varargs/invvarargs.html
See this collection of "wacky ideas" by the C FAQ list maintainer: http://c-faq.com/varargs/wacky.html
Addendum: see this former SO question: How to call functions by their pointers passing multiple arguments in C?
...which mentions "libffi": http://sourceware.org/libffi/
Specifics matter. Especially when talking about how something works, and even more so when we consider why something works. Currently, as I understand it, EVERYTHING in C is passed by value. NOTHING is passed by reference. Some programmers mention that arrays in C are passed by reference.
But as per my limited understanding,
Even if we pass an array to a function like this void traverse(int arr[4]);, it is actually being taken in as a copy of the pointer variable storing the location in memory of the first element in that array. It is then dereferenced inside the function, but the initial value being passed is actually a local variable. Since memory allocated to arrays in the program stack would be contiguous, the compiler is able to make square bracket notation work as well as pointer arithmetic.
This and passing by reference are not the same thing to me. I would think this is an important distinction.
But on the other hand, we can then just say that everything in computing is passed by value, since something like Java would do the same in a more subtle manner. And it is actually just simulating a pass by reference. Please advise.
At the level of bits in the computer, arguments can only be passed by value. Bits representing some argument are written to a processor register or memory location designated as the place to pass an argument. Passing by reference is a construct built upon passing by value by using an address as the value that is passed. Passing an address can be implemented automatically or manually. Both methods are pass-by-reference.
When we pass some entity by passing its address instead of passing its value directly, that is called pass by reference. This terminology long antedates the creation of “references” in C++. In assembly language, when we load the address of some thing into a register to pass it to a function, that was, and is, called pass by reference. The C standard specifies a pointer provides a reference to an entity (C 2018 6.2.5 20). So, when we have a pointer to an object, we have a reference to an object, and when we pass the pointer to a function, we are passing a reference to the object to the function.
Some languages automated pass-by-reference. FORTRAN passes everything by reference except for some special syntax for calling routines outside FORTRAN. However, whether passing-by-reference is implemented as an automatic feature of the programming language, by a programmer manually loading an address in assembly language, or by a programmer manually requesting an address with a language operator such as C’s &, when a reference to an object is passed, then the object is passed by reference.
C++ created a new type that it called a “reference,” but this was a new use of the word. The C++ meaning of “reference” applies to C++ only. It does not change the existing use of that word outside the context of C++. Outside of C++, “reference” has its ordinary English meaning of providing information on another thing.
Regarding your specific question about passing an array in C,
in C, an array argument is automatically converted to the address of its first element, and this address is typically used to access the entire array. So the array is in fact passed by reference. Describing this as an automatic conversion to a pointer is merely documenting the details. The effect is the same: The function is given access to the object the caller designated by providing a reference to it.
Further, any dispute over the meaning of “pass by reference” is merely one about terminology, not about the actual mechanisms used in the computer.
I am presently in a case where I need to call a lot of function pointers that has been extracted at runtime. The problem is that the arguments are unknown at compilation time.
But, at runtime I receive datas that allows me to know the arguments of the function and I can even store the arguments in a char* array. The problem is that I don't have a function pointer model to cast it into.
In high level language, I know there is function like "InvokeMethode(String name,Byte[] args)" that interpret the bytes array like arguments. Since reflection does not exist in C, I have no hope to see this with a function pointer.
One solution that I have in mind (and it's really bad), is to create a model of function pointer at compilation time that will cast in a "hardcoded way" the ptr to the right type to use like this:
void callFunc64Bits(void* funcPtr,long long args);
void callFuncVoid(void* funcPtr);
The problem is that I will have to create like 100 function like this that will cast the pointer correctly.
Is there a way to do it more efficiently?
Thank you very much!
This is a hard problem without, unfortunately, good or easy answers.
See this former SO question: Run-time parameters in gcc (inverse va_args/varargs)
See this C FAQ question: http://c-faq.com/varargs/invvarargs.html
See this collection of "wacky ideas" by the C FAQ list maintainer: http://c-faq.com/varargs/wacky.html
Addendum: see this former SO question: How to call functions by their pointers passing multiple arguments in C?
...which mentions "libffi": http://sourceware.org/libffi/
I am trying to implement an interpreter. I'd love to go with GCC first class labels to make it threaded code, but I should hold on to a standard this time, so naturally I am left with function table. So, I'm doing this:
unsigned short int FUN_TABLE[MAX_FUN] (void*);
And I want to fill it with functions, each getting pointer to its operands, doing its part, returning length of the whole instruction in memory to a dispatcher.
The thing is, I can't even compile it due to the following error: declaration of FUN_TABLE as array of functions. Considering it is exactly what I am trying to achieve, why is this an error, why should I pay it attention, and if I shouldn't, how to suppress it in elegant and standardized manner?
You can define an array of function pointers like this (pseudocode):
int (*funcArr2[10])(param, param, ...) = {NULL};
However, you should be aware that this means that all these functions have the same set of arguments. You can not declare an array with function pointers to totall different functions with regard to their signature.
GCC is telling you: "there is no such thing as an array of functions".
Considering it is exactly what I am trying to achieve, why is this an error, why should I pay it attention
Because you are trying to achieve something that does not exist in the C language. But instead, you can achieve the desired functionality through an array of function pointers.
The syntax of declaring a function pointer is
return_type (*func_ptr_name)(parameters)
and the syntax for declaring an array of function pointers is
return_type (*func_ptr_name[n])(parameters)
Since that syntax is quite obscure, you will not want to use it. The solution is to use typedefs:
typedef unsigned short (*func_table_t)(void*);
// declare an array of function pointers, using readable syntax:
func_table_t func_table [MAX_FUNC] =
{
&some_function,
&some_other_function,
...
};
Arrays of functions aren't legal. Your easiest work around would be an array of pointers to functions -- but this implies that each function being pointed to from the array has the same signature.
Example available at ideone.com:
int passByConstPointerConst(MyStruct const * const myStruct)
int passByValueConst (MyStruct const myStruct)
Would you expect a compiler to optimize the two functions above such that neither one would actually copy the contents of the passed MyStruct?
I do understand that many optimization questions are specific to individual compilers and optimization settings, but I can't be designing for a single compiler. Instead, I would like to have a general expectation as to whether or not I need to be passing pointers to avoid copying. It just seems like using const and allowing the compiler to handle the optimization (after I configure it) should be a better choice and would result in more legible and less error prone code.
In the case of the example at ideone.com, the compiler clearly is still copying the data to a new location.
In the first case (passing a const pointer to const) no copying occurs.
In the second case, copying does occur and I would not expect that to be optimized out if for no other reason because the address of the object is taken and then passed through an ellipsis into a function and from the point of view of the compiler, who knows what the function does with that pointer?
More generally speaking, I don't think changing call-by-value into call-by-reference is something compilers do. If you want copy by reference, implement it yourself.
Is it theoretically possible that a compiler could detect that it could just convert the function to be pass-by-reference? Yes; nothing in the C standard says it cannot..
Why are you worrying about this? If you are concerned about performance, has profiling shown copy-by-value to be a significant bottleneck in your software?
This topic is addressed by the comp.lang.c FAQ:
http://c-faq.com/struct/passret.html
When large structures are passed by value, this is commonly optimized by actually passing the address of the object rather than a copy. The callee then determines whether a copy needs to be made, or whether it can simply work with the original object.
The const qualifier on the parameter makes no difference. It is not part of the type; it is simply ignored. That is to say, these two function declarations are equivalent:
int foo(int);
int foo(const int);
It's possible for the declaration to omit the const, but for the definition to have it and vice versa. The optimization of the call cannot hinge on this const in the declaration. That const is not what creates the semantics that the object is passed by value and hence the original cannot be modified.
The optimization has to preserve the semantics; it has to look as if a copy of the object was really passed.
There are two ways you can tell that a copy was not passed: one is that a modification to the apparent copy affects the original. The other way is to compare addresses. For instance:
int compare(struct foo *ptr, struct foo copy);
Inside compare we can take the address of copy and see whether it is equal to ptr. If the optimization takes place even though we have done this, then it reveals itself to us.
The second declaration is actually a direct request by the user to receive a copy of the passed struct.
const modifier eliminates the possibility of any modifications made to the local copy, however, it is does not eliminate all the reasons for copying.
Firstly, the copy has to maintain its address identity, meaning that inside the second function the &myStruct expression should produce a value different from the address of any other MyStruct object. A smart compiler can, of course, detect the situations that depend on the address identity of the object.
Secondly, aliasing presents another problem. Imagine that the program has a global pointer MyStruct *global_struct and inside the second function someone modifies the *global_struct. There's a possibility that the *global_struct is the same struct object that was passed to the function as an argument. If no copy was made, the modifications made to *global_struct will be visible through the local parameter, which is a disaster. Aliasing issues are much more difficult (and in general case impossible) to resolve at compilation time, which is why compilers usually won't be able to optimize out the copying.
So, I would expect any compiler to perform the copying, as requested.