Earlier quoted context omitted.
Unfortunately this is differently wrong in C# (and many other modern languages). arr here is not an array at all, but is actually a reference to an array and has different semantics from the the corresponding C declaration. This is not just being pedantic: using the same syntax for values and references does lead to confusion. At least C# has actual value types and 'ref' (but not value type arrays AFAIK), in Java thi…
I wouldn't agree to call it "wrong", since we're talking about languages that are trying to discourage you from doing your own memory management *(C#, that is, but I'd say this applies to any language running in a VM with gc, really). Thus, in such languages, there shouldn't be a conceptual or syntactical difference between values and references. The fact that C# allows to differentiate them from each other is a leak…
A convenient untruth: Array notation in C is a lie
161–170 of 176 posts
Re: A convenient untruth: Array notation in C is a lie
#162Earlier quoted context omitted.
> None of those 'lies' have anything to do with assembler. They do. Lets take a look at the very first one. "Array name is just a pointer". Assebler "array" is a name of a label. So its just named address in memory. Or we can alternatively say, that assembler array is constant pointer. `sizeof' returns size of array in bytes? Hmm... maybe that because main C abstraction for memory is the assembler one: memory is a co…
From an assembler point of view a structure of N elements of type T and an array of T[N] have exactly the same layout and are accessed in exactly the same way [1], but in C have wildly different semantics. Sizeof behaves exactly the same way for structs and arrays, so it is one of the few things in C that treat arrays "correctly". [1] although usually the offset is constant for a struct field access.
Can you show it with example? I'm not sure what you mean exactly.
Look:
struct {
int a, b, c;
} foo;
int *pfoo = (int*)&foo;
printf("%d, %d, %d\n", pfoo[0], pfoo[1], pfoo[2]);
Code like this can have problems due to alignment, but at my opinion its not "wildly different semantics".Re: A convenient untruth: Array notation in C is a lie
#163Earlier quoted context omitted.
From an assembler point of view a structure of N elements of type T and an array of T[N] have exactly the same layout and are accessed in exactly the same way [1], but in C have wildly different semantics. Sizeof behaves exactly the same way for structs and arrays, so it is one of the few things in C that treat arrays "correctly". [1] although usually the offset is constant for a struct field access.
> but in C have wildly different semantics. Can you show it with example? I'm not sure what you mean exactly. Look: struct { int a, b, c; } foo; int *pfoo = (int*)&foo; printf("%d, %d, %d\n", pfoo[0], pfoo[1], pfoo[2]); Code like this can have problems due to alignment, but at my opinion its not "wildly different semantics".
Re: A convenient untruth: Array notation in C is a lie
#164Earlier quoted context omitted.
> but in C have wildly different semantics. Can you show it with example? I'm not sure what you mean exactly. Look: struct { int a, b, c; } foo; int *pfoo = (int*)&foo; printf("%d, %d, %d\n", pfoo[0], pfoo[1], pfoo[2]); Code like this can have problems due to alignment, but at my opinion its not "wildly different semantics".
In addition to being UB, the example doesn't illustrate the issue: arrays in C are not first class as they can't be passed by value and can't be assigned. The decay-to-pointer thing that prevent this regularity has nothing to do with asm.
Yes, its UB. But I'm not persuade you to use this UB in real code: in real C code use offsetof from stddef.h. The only thing I want to say is: this code would work everywhere (if you pay attention to alignment). And its not coincidence by some chance: C mimics asm, because C needs to be 100% predictable to coder. Because asm use simpliest and the most obvious abstractions, with predictable runtime costs. C also goes this way. So its inevitable for my code to work. With some precautions, but it would work everywhere.
> the example doesn't illustrate the issue...
Yes, I suggested it, and I asked you for some illustrative example, because I can't understand your reasoning from "arrays are not first class" to "nothing to do with asm". I see it other way: "arrays are not first class" is "asm mode".
Re: A convenient untruth: Array notation in C is a lie
#165Earlier quoted context omitted.
In addition to being UB, the example doesn't illustrate the issue: arrays in C are not first class as they can't be passed by value and can't be assigned. The decay-to-pointer thing that prevent this regularity has nothing to do with asm.
> In addition to being UB, Yes, its UB. But I'm not persuade you to use this UB in real code: in real C code use offsetof from stddef.h. The only thing I want to say is: this code would work everywhere (if you pay attention to alignment). And its not coincidence by some chance: C mimics asm, because C needs to be 100% predictable to coder. Because asm use simpliest and the most obvious abstractions, with predictable…
> I asked you for some illustrative example,
foo(T x) { x[0] = 1; }
T x = {0};
foo(x);
assert(x[0] == 0);
The assertion fails for T = char[1], but succeed for T=std::array; You could construct a similar example in pure C.std::array and C arrays compile down to the exact same code for access, have the exact same layout, etc, but C array are not copyable and assignable and implicitly convert to pointers without any good reason. This has nothing to do with assembler whatsoever.
Re: A convenient untruth: Array notation in C is a lie
#166Earlier quoted context omitted.
Unfortunately this is differently wrong in C# (and many other modern languages). arr here is not an array at all, but is actually a reference to an array and has different semantics from the the corresponding C declaration. This is not just being pedantic: using the same syntax for values and references does lead to confusion. At least C# has actual value types and 'ref' (but not value type arrays AFAIK), in Java thi…
I wouldn't agree to call it "wrong", since we're talking about languages that are trying to discourage you from doing your own memory management *(C#, that is, but I'd say this applies to any language running in a VM with gc, really). Thus, in such languages, there shouldn't be a conceptual or syntactical difference between values and references. The fact that C# allows to differentiate them from each other is a leak…
It's not a leaky abstraction, it's a very specific design choice for performance reasons. Java also has this dichotomy between types, and for the same reason, although I believe they only delineate between primitive/non-primitive.
Re: A convenient untruth: Array notation in C is a lie
#167Earlier quoted context omitted.
Right, in a language with dependent types there is a type-level difference between int[5] and int[7], but c is not such a language, therefore using a syntax that encourages the mistaken notion that there is a type-level difference between int[5] and int[7] would be misleading.
Saying int[5] and int[7] are the same type because the compiler doesn't enforce the difference is like saying JavaScript is untyped because there is no compiler to enforce types at all. Regardless of what the spec or the compiler says, you the programmer absolutely need to treat them separately. Especially in a language like C, where arrays aren't even self-describing at runtime.
Re: A convenient untruth: Array notation in C is a lie
#168Earlier quoted context omitted.
Right, in a language with dependent types there is a type-level difference between int[5] and int[7], but c is not such a language, therefore using a syntax that encourages the mistaken notion that there is a type-level difference between int[5] and int[7] would be misleading.
A language doesn't need dependent types to make fixed-size arrays of differing size count as incompatible types. Rust does this, for example: // error: expected an array with a fixed size of 5 // elements, found one with 7 elements let x: [i32; 5] = [1,2,3,4,5,6,7];
like, you can have a type (a, b), and b can, of course, be of type (a, b), b again having type (a, b), and so on. then you always carry around the length encoded in the type, and it can be checked like above.
ghc has a limit on tuple sizes, and haskell makes no type distinction between [a] based on the number of elements in it, and it isn't dependently typed.
but again i don't know rust.
Re: A convenient untruth: Array notation in C is a lie
#169Earlier quoted context omitted.
A language doesn't need dependent types to make fixed-size arrays of differing size count as incompatible types. Rust does this, for example: // error: expected an array with a fixed size of 5 // elements, found one with 7 elements let x: [i32; 5] = [1,2,3,4,5,6,7];
i don't know rust, but i read a bit about fixed size arrays in it and the fact that 32 is the largest fixed size array makes me suspicious that it works like a pair. you can do this without depending on a value, because the length is encoded in the type. like, you can have a type (a, b), and b can, of course, be of type (a, b), b again having type (a, b), and so on. then you always carry around the length encoded in…
> i read a bit about fixed size arrays in it and the fact
> that 32 is the largest fixed size array
This is exceptionally mistaken, where did you read it? Arrays in Rust top out at the maximum value of a platform-sized pointer, which is either 2^32 or 2^64 depending on platform.Re: A convenient untruth: Array notation in C is a lie
#170Earlier quoted context omitted.
> In addition to being UB, Yes, its UB. But I'm not persuade you to use this UB in real code: in real C code use offsetof from stddef.h. The only thing I want to say is: this code would work everywhere (if you pay attention to alignment). And its not coincidence by some chance: C mimics asm, because C needs to be 100% predictable to coder. Because asm use simpliest and the most obvious abstractions, with predictable…
> this code would work everywhere it does not, it will be miscompiled by modern compilers. > I asked you for some illustrative example, foo(T x) { x[0] = 1; } T x = {0}; foo(x); assert(x[0] == 0); The assertion fails for T = char[1], but succeed for T=std::array ; You could construct a similar example in pure C. std::array and C arrays compile down to the exact same code for access, have the exact same layout, etc, b…