Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

后端 未结 10 1412
终归单人心
终归单人心 2020-11-22 06:59

This is what I found during my learning period:

#include
using namespace std;
int dis(char a[1])
{
    int length = strlen(a);
    char c = a         


        
相关标签:
10条回答
  • 2020-11-22 07:36

    The problem and how to overcome it in C++

    The problem has been explained extensively by pat and Matt. The compiler is basically ignoring the first dimension of the array's size effectively ignoring the size of the passed argument.

    In C++, on the other hand, you can easily overcome this limitation in two ways:

    • using references
    • using std::array (since C++11)

    References

    If your function is only trying to read or modify an existing array (not copying it) you can easily use references.

    For example, let's assume you want to have a function that resets an array of ten ints setting every element to 0. You can easily do that by using the following function signature:

    void reset(int (&array)[10]) { ... }
    

    Not only this will work just fine, but it will also enforce the dimension of the array.

    You can also make use of templates to make the above code generic:

    template<class Type, std::size_t N>
    void reset(Type (&array)[N]) { ... }
    

    And finally you can take advantage of const correctness. Let's consider a function that prints an array of 10 elements:

    void show(const int (&array)[10]) { ... }
    

    By applying the const qualifier we are preventing possible modifications.


    The standard library class for arrays

    If you consider the above syntax both ugly and unnecessary, as I do, we can throw it in the can and use std::array instead (since C++11).

    Here's the refactored code:

    void reset(std::array<int, 10>& array) { ... }
    void show(std::array<int, 10> const& array) { ... }
    

    Isn't it wonderful? Not to mention that the generic code trick I've taught you earlier, still works:

    template<class Type, std::size_t N>
    void reset(std::array<Type, N>& array) { ... }
    
    template<class Type, std::size_t N>
    void show(const std::array<Type, N>& array) { ... }
    

    Not only that, but you get copy and move semantic for free. :)

    void copy(std::array<Type, N> array) {
        // a copy of the original passed array 
        // is made and can be dealt with indipendently
        // from the original
    }
    

    So, what are you waiting for? Go use std::array.

    0 讨论(0)
  • 2020-11-22 07:36

    This is a well-known "feature" of C, passed over to C++ because C++ is supposed to correctly compile C code.

    Problem arises from several aspects:

    1. An array name is supposed to be completely equivalent to a pointer.
    2. C is supposed to be fast, originally developerd to be a kind of "high-level Assembler" (especially designed to write the first "portable Operating System": Unix), so it is not supposed to insert "hidden" code; runtime range checking is thus "forbidden".
    3. Machine code generrated to access a static array or a dynamic one (either in the stack or allocated) is actually different.
    4. Since the called function cannot know the "kind" of array passed as argument everything is supposed to be a pointer and treated as such.

    You could say arrays are not really supported in C (this is not really true, as I was saying before, but it is a good approximation); an array is really treated as a pointer to a block of data and accessed using pointer arithmetic. Since C does NOT have any form of RTTI You have to declare the size of the array element in the function prototype (to support pointer arithmetic). This is even "more true" for multidimensional arrays.

    Anyway all above is not really true anymore :p

    Most modern C/C++ compilers do support bounds checking, but standards require it to be off by default (for backward compatibility). Reasonably recent versions of gcc, for example, do compile-time range checking with "-O3 -Wall -Wextra" and full run-time bounds checking with "-fbounds-checking".

    0 讨论(0)
  • 2020-11-22 07:39

    It is a quirk of the syntax for passing arrays to functions.

    Actually it is not possible to pass an array in C. If you write syntax that looks like it should pass the array, what actually happens is that a pointer to the first element of the array is passed instead.

    Since the pointer does not include any length information, the contents of your [] in the function formal parameter list are actually ignored.

    The decision to allow this syntax was made in the 1970s and has caused much confusion ever since...

    0 讨论(0)
  • 2020-11-22 07:40

    First, C never checks array bounds. Doesn't matter if they are local, global, static, parameters, whatever. Checking array bounds means more processing, and C is supposed to be very efficient, so array bounds checking is done by the programmer when needed.

    Second, there is a trick that makes it possible to pass-by-value an array to a function. It is also possible to return-by-value an array from a function. You just need to create a new data type using struct. For example:

    typedef struct {
      int a[10];
    } myarray_t;
    
    myarray_t my_function(myarray_t foo) {
    
      myarray_t bar;
    
      ...
    
      return bar;
    
    }
    

    You have to access the elements like this: foo.a[1]. The extra ".a" might look weird, but this trick adds great functionality to the C language.

    0 讨论(0)
  • 2020-11-22 07:42

    It's allowed for compilers to be able to check whether the size of array passed is the same as what expected. Compilers may warn an issue if it's not the case.

    0 讨论(0)
  • 2020-11-22 07:43

    One thing that hasn't been answered yet is the actual question.

    The answers already given explain that arrays cannot be passed by value to a function in either C or C++. They also explain that a parameter declared as int[] is treated as if it had type int *, and that a variable of type int[] can be passed to such a function.

    But they don't explain why it has never been made an error to explicitly provide an array length.

    void f(int *); // makes perfect sense
    void f(int []); // sort of makes sense
    void f(int [10]); // makes no sense
    

    Why isn't the last of these an error?

    A reason for that is that it causes problems with typedefs.

    typedef int myarray[10];
    void f(myarray array);
    

    If it were an error to specify the array length in function parameters, you would not be able to use the myarray name in the function parameter. And since some implementations use array types for standard library types such as va_list, and all implementations are required to make jmp_buf an array type, it would be very problematic if there were no standard way of declaring function parameters using those names: without that ability, there could not be a portable implementation of functions such as vprintf.

    0 讨论(0)
提交回复
热议问题