Live data from Hacker News

A convenient untruth: Array notation in C is a lie

blog.feabhas.com

131–140 of 176 posts

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

#131
> Why is this [array assignment] failing? Because the array’s name is a lie! Using a variable as an expression normally yields its value, but in the case of arrays the array name yields a pointer (to the first element; which is at least reasonable)

Sorry, no; the assignment fails because an array isn't a modifiable lvalue. Array assignment simply isn't supported.

If array assignment were supported the array-to-pointer conversion ("decay") could be suppressed in that case to make it work. Just like it is suppressed when an array is the operand of sizeof of & (address-of).

Assignment of arrays is supported when they are struct/union members:

  struct wrapper {
    int a[5];
  } x = { 0 }, y = x;
We can return this from a function, too.

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

#132
post #71

Why did people think otherwise? Chapter 5 of K&R [1] is titled Pointers and Arrays and basically explains that arrays and pointers are equivalent. [1]: https://www.amazon.com/Programming-Language-Brian-W-Kernigha...

The point of the article is that sometimes they're not equivalent, and that creates a lot of confusion. Please read it before commenting on it.

Arrays and pointers are never equivalent. One is a clump of like-sized objects allocated consecutively; the other is a referential type indicating the location of an object or function.

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

#133
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 will now duck and get far away from the internet, in fear of all the hateful comments explaining to me how I am wrong, and apparently just don't understand the superior beauty of complicated C syntax. I am going to be that person :-) One phrase – "declarations mirror use". In a declaration, you use the same set of operators around the declared object that you would use in a normal expression. All of these operato…

I have been writing C and C++ for a little more than 10 years now and this is the first I have heard "declarations mirror use". I understood that was the case, but why is the phrase important.

To me understanding the actual types involved is more important than getting the declaration to look some specific way. (So I always jammed the star next to type and did whatever else I though would most ease expressing types)

I am also the kind of developer who who have declared it as:

std::array arr;

or

std::vector arr;

depending on if X was known at compile time. Because I want to give the compiler as many chances to call out my mistakes as possible.

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

#134
post #14

These facts is not a lies. They are inconviniences which one can see looking on C from perspective of higher level language. But if you learn how to program with assembler before studing C, than all these facts would look like obvious and convinient syntactic sugar. Maybe in C++ these facts become inconvinient, because of C++ pretending to be higher level language than crossplatform assembler. But if it is a problem,…

None of those 'lies' have anything to do with assembler. C deviated from regularity for the sake of convenience in some cases, and now we are stuck with those bad decisions forever.

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

#135
I was lucky to learn C with pointers first, and then arrays. When you think about it as just chunks of memory, it all makes sense and is easier to reason about what the cpu will do. This is another example of a "simplifying abstraction" that is more misleading than simplifying.

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

#136

C now has static array indices. For example void func(int arr[static 8]) {} imposes a limit on the size of the array that can be passed as an argument (you cannot pass an array of 7 or fewer elements.) I'd suggest that to the author, but given the article, I fear it may give him a heart attack.

I know they're called static array indices, and they're called that because of the use of the keyword `static`, but they don't have to be compile time constant at all (and checks aren't performed at compile time, IIRC). You can have the following: void foo(size_t len, int arr[static len]); Which is really useful in asserting that you won't pass in the null pointer at runtime (so you can remove any `if (arr) {}` check…

Checks against constants are indeed compile-time.

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

#137
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…

Well, had C been really strongly-typed then the hypothetical 'int[5]' and 'int[7]' would have been different types, and 'int[]' would be the size-agnostic type for an array.

Then you could easily get creature comforts such as:

  typedef uint8_t[16] guid_t;
  typedef uint8_t[20] sha1_digest_t;
These typedefs would then have copy assignment, pass-by-value semantics and everything else you'd expect from value types.

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

#138
post #69

In the last example, > char string[] = "Hello world"; I thought that gives out warning these days. Isn't the proper type of a string literal the following? > const char string[] = "Hello world"; Therefore, you can't really modify individual characters there.

C string literals are " char * ". C++ string literals are " const char * " (one of the minor incompatibilities between the languages). They ought to be "const char[]" but aren't. And, the behavior of "char[]" should be the same as "struct { char[] }", but it isn't.

They actually are proper arrays in C++ [1], although, as usual, they decay to pointers faster than an unstable particle.

[1]: https://godbolt.org/g/ZWISCu

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

#139

Earlier quoted context omitted.

Thanks for the clear explanation. This makes sense. I do have a tangential question. I have read that the reason for this declaration syntax is that it was easier form compilers and compiler writers to parse. How does this declaration syntax facilitate parsing exactly? I fail to see why this is.

The advantage is that you don't introduce any new operators or syntactic forms which would only be used in declarations. This means a smaller set of tokens and a smaller set of syntactic forms. Being able to parse an expression like (*arr[i])(42) means that you can use pretty much the same machinery to parse int (*arr[SIZE])(int a)

This is awesome. Thank you.
Post reply on HN