3 ms·
Fortran has a lot more (N-dimensional) array logic intrinsic to the language than C or C++ does, and in general, Fortran has a fair number of "little" things th
by jcranmer 3y ago
Fortran has a lot more (N-dimensional) array logic intrinsic to the language than C or C++ does, and in general, Fortran has a fair number of "little" things that can add up for optimization:
* Fortran arrays do not alias by default. (This is the most well-known, and is indeed repeated in the answers on StackOverflow)
* Fortran N-D array indexes are UB if they go out-of-bounds in a way that isn't true for most other languages. In C, if you have a declaration `int x[2][3];`, the expression `x[0][4]` is a legal way to access one of the elements--it's only UB to go outside the bounds of x as a whole, not individual rows. In Fortran, the equivalent expression (well, modified because Fortran is column-major) is illegal.
* Fortran has built in array expressions--you can express a vector addition just by adding the arrays themselves. This makes it easier to autovectorize.
- pklausler 3y agoFortran's dummy arguments can (generally) be assumed in the scope of a subprogram to not alias, whether arrays or not. The burden is on the programmer of calls to procedures to not associate any of its dummy arguments that are modified during the call with data that might be associated with any other dummy argument.
- KeplerBoy 3y ago> In C, if you have a declaration `int x[2][3];`, the expression `x[0][4]` is a legal way to access one of the elements Is it really? Does the C-compiler guarantee that your 6 ints will be stored in a contiguous memory area?
- jcranmer 3y agoYes. A[i] in C is exactly equivalent to *(A + i). (Incidentally, this means that 2[x] is a legal expression in C).
- KeplerBoy 3y agoOf course, that part is clear. The question is, if the two rows are guaranteed to be contiguous in memory. If using heap allocated memory, one could easily construct a counterexample (i'm not sure how the stack allocated array behaves, i guess it works because it's the sane choice, but not strictly guaranteed): int *x; int numRows = 2; int numCols = 3; x = (int *)malloc(numRows * sizeof(int )); for (int i = 0; i < numRows; i++) { x[i] = (int )malloc(numCols * sizeof(int)); } // This could segfault x[0][4] = 42;
- jcranmer 3y agoYes, it's a multidimensional array, everything is required to be consecutively allocated. (See 6.5.2.1 for more details). `int[2][3]` is 6 integer objects consecutively allocated (as 3 arrays of 2 arrays of integers), not 3 pointers to arrays of 2 integers.
- KeplerBoy 3y agoThanks for pointing to the actual section. Good to know.
- Someone 3y ago> (Incidentally, this means that 2[x] is a legal expression in C) Even weirder, for that declaration int x[2][3]; I think the following are legal expressions: 0[1[x]] 1[x][0] Or is there something in the language that makes that break parsing?
- LegionMammal978 3y ago> In C, if you have a declaration `int x[2][3];`, the expression `x[0][4]` is a legal way to access one of the elements--it's only UB to go outside the bounds of x as a whole, not individual rows. Even though multidimensional arrays are laid out contiguously in C/C++, it doesn't follow that indexing can traverse from one row to the next. By C17 6.5.6/8, pointer-integer addition can only create pointers to other elements (or one past the last element) of the same array object that the original pointer came from. However, an int[2][3] array has two int[3] arrays as elements, and each of those arrays has three int objects as elements. The int objects are not all elements of the same array (the standard's definition of an array element, 6.2.5/20, doesn't apply recursively), so you aren't allowed to index between them with expressions like (x[0] + 4). Compilers seem to be pretty lenient about this in practice, though, only optimizing out out-of-bounds accesses when they exit the complete object. But at least Clang's UBSan will complain if you try to index between rows [0]. [0] https://godbolt.org/z/GYosP39Mc https://godbolt.org/z/GYosP39Mc