Live data from Hacker News

A convenient untruth: Array notation in C is a lie

blog.feabhas.com

41–50 of 176 posts

Re: A convenient untruth: Array notation in C is a lie

#41
post #5

Is this article a sign that C has fallen out of mainstream use?

What is "mainstream" these days?

If you're serious, or for those who may indeed be in a bit of an echo chamber, the Tiobe index, while it may have much to criticize, is at least approximately correct: http://www.tiobe.com/tiobe-index/ Which yields Java being larger than C and C++ combined, which are the next two. Then Python. Then probably a long list of things whose order should not be taken too literally. All I'm trying to show here is that, yes, Java, C, and C++ are still the dominant languages. This is shown by a lot of other metrics too.

Re: A convenient untruth: Array notation in C is a lie

#43
post #21

The equivalent in C# always made more sense to me (not comparing memory or allocation model between the languages, but simply syntax in relation to a person reading it): int[] arr = new int[5]; // C# int arr[5]; // C The fact that the brackets go on the datatype always made more sense to me, after all, I want to refer to memory of a certain cell size (as indicated by int). I realize that there is a lot of stuff going…

I don't agree with: int[5] arr; being a more readable syntax. The problem is that if you later have: int[7] arr2; It would make sense that arr and arr2 are different types (as the thing on the left is different) while they are the same type and you should be able (hopefully!) to use them as arguments to the same function. On the other hand I agree that: int* arr; makes more sense than more commonly used: int *arr; al…

I mean, int[5] and int[7] would be different types, and lots of bugs happen from passing something besides the appropriate array type to a function.

That being said, most languages which disambiguate between int[5] and int[7] provide some kind of polymorphism (and usually store it as a struct of size + data, to enable that).

For example: you can define a first function that goes from t[N]->t pretty easily, and it would operate on both int[5] and int[7] (returning an int).

Re: A convenient untruth: Array notation in C is a lie

#44
post #2

It's not that convenient an untruth seeing as these are probably some of the first things you learn in C, and some of the first gotchas that'll getcha. Having said that, the article was well written.

I think it's more likely the reaction to someone who uses magic languages that perform complicated actions over a simple assignment. If you think of C as a high-level assembly language whose assignment instruction is converted into a single machine instruction, this type of behavior is not so surprising.

Re: A convenient untruth: Array notation in C is a lie

#45
post #21

The equivalent in C# always made more sense to me (not comparing memory or allocation model between the languages, but simply syntax in relation to a person reading it): int[] arr = new int[5]; // C# int arr[5]; // C The fact that the brackets go on the datatype always made more sense to me, after all, I want to refer to memory of a certain cell size (as indicated by int). I realize that there is a lot of stuff going…

I don't agree with: int[5] arr; being a more readable syntax. The problem is that if you later have: int[7] arr2; It would make sense that arr and arr2 are different types (as the thing on the left is different) while they are the same type and you should be able (hopefully!) to use them as arguments to the same function. On the other hand I agree that: int* arr; makes more sense than more commonly used: int *arr; al…

> It would make sense that arr and arr2 are different types (as the thing on the left is different) while they are the same type and you should be able (hopefully!) to use them as arguments to the same function.

arr and arr2 are indeed distinct types. They are of type int[5] and int[7]. You can see this by checking that they have different sizes, or that `printf("%s\n", std::is_same::value ? "true" : "false");` will outputs `false` on your screen.

Both of them decay into a pointer to int, that is why people commonly confuse them with pointers. But they are pointer types; they are distinct types on their own.

Re: A convenient untruth: Array notation in C is a lie

#47
post #46

So the only difference between an Array and an *int is how sizeof() behaves? And how do I pass my Array to a function without losing sight of its size?

I don't believe that's possible. Except 'by hand'; pass the size as a separate parameter.

Re: A convenient untruth: Array notation in C is a lie

#48
post #39

This gets weird when you compare it to how structs work in C. Both are complex data types, so I sometimes forget that array semantics are totally different to struct/union semantics. Unlike arrays, in ANSI C, structs are real value types. You can pass them by-value to functions, return them by-value from functions and assign them by-value to variables of the same type. Also, structs never work like pointers to themse…

Worth noting that you can always wrap an array in a structure and kick it around in your program happily, as if it's how the language should've been.

    struct { int a[5]; } arr5 = {{4, 3, 2}};
What's a bit weird though, is that while initialization like above is possible, assignment of a contsant is not as smooth in C, you will have to typedef your structure and use it in a typecast expression:

    typedef struct { int a[5]; } Array5;
    ...
    arr5 = (Array5){{4, 3, 2}};

Re: A convenient untruth: Array notation in C is a lie

#50
post #46

So the only difference between an Array and an *int is how sizeof() behaves? And how do I pass my Array to a function without losing sight of its size?

Short answer: For the user? yes. For the type system? no. To keep track of the length of the array, you can pass the number of elements as a second parameter to the function.

Long answer: For arrays with a declared length, the length is included in its type (6.2.5.20, page 42, [1]). Therefore, the type of "int a[5]" is "array of 5 integers". The type of "int*" is "pointer to integer". For arrays without a length, the type is considered 'incomplete' (6.2.5.22).

So the C typing system considers these 2 different types.

"Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue." (6.3.2.1.3)

sizeof is essentially an exception.

"The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer." (6.5.3.4.2)

And that's how sizeof is defined. Because it uses the type to compute the size, and the type of arrays include their length, and the type of arrays doesn't change in sizeof expressions, sizeof will return the total number of bytes of all the elements of the array.

[1] C11 standard (draft): http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf

Post reply on HN