Этот ответ содержит ошибки. Как уже отмечалось, не существует решения этой проблемы, которое гарантированно будет работать при внедрении новых платформ, кроме использования метода «10-элементный массив».
Ответ от solidsun работал хорошо, пока я не пошел на компиляцию с 64-битной архитектурой. Это вызвало ошибку:
EXC_BAD_ADDRESS type EXC_I386_GPFLT
Решением было использование немного другого подхода для передачи списка аргументов в метод:
+ (id)stringWithFormat:(NSString *)format array:(NSArray*) arguments;
{
__unsafe_unretained id * argList = (__unsafe_unretained id *) calloc(1UL, sizeof(id) * arguments.count);
for (NSInteger i = 0; i < arguments.count; i++) {
argList[i] = arguments[i];
}
NSString* result = [[NSString alloc] initWithFormat:format, *argList] ;// arguments:(void *) argList];
free (argList);
return result;
}
Это работает только для массивов с одним элементом
Компилятор превратит
index[array]
в
*(index + array)
. При обычном синтаксисе он превратит
array[index]
в
*(array + index)
, и вы увидите, что оба выражения дают одно и то же значение. Это справедливо как для C, так и для C ++.
С самых ранних дней C выражение a [i]
было просто адресом [0], добавленным к i (увеличенное в масштабе размером a [0]), а затем ссылка на него отменяется. Фактически, все они были эквивалентны:
a[i]
i[a]
*(a+i)
====
Единственное, что меня беспокоит, - это фактическое разыменование. Хотя все они выдают один и тот же адрес , разыменование может быть проблемой, если типы
a
иi
различны.Например:
int i = 4;
long a[9];
long x = a[i]; //get the long at memory location X.
long x = i[a]; //get the int at memory location X?
Я на самом деле не проверял такое поведение, но вы можете остерегаться этого. Если он действительно изменит то, что лишается ссылки, это, вероятно, вызовет всевозможные проблемы с массивами объектов.
====
Обновление:
Вы, вероятно, можете спокойно игнорировать бит выше между =====
строк. Я тестировал его под Cygwin с коротким и длинным, и мне кажется, все в порядке, поэтому я думаю, что мои опасения были необоснованными, по крайней мере, для основных случаев. Я до сих пор не знаю, что происходит с более сложными, потому что я вряд ли когда-либо захочу этого делать.
In C and C++ (with array being a pointer or array) it is a language feature: pointer arithmetic. The operation a[b] where either a or b is a pointer is converted into pointer arithmetic: *(a + b). With addition being symetrical, reordering does not change meaning.
Now, there are differences for non-pointers. In fact given a type A with overloaded operator[], then a[4] is a valid method call (will call A::operator ) but the opposite will not even compile.
As Matthew Wilson discusses in Imperfect C++, this can be used to enforce type safety in C++, by preventing use of DIMENSION_OF()
-like macros with instances of types that define the subscript operator, as in:
#define DIMENSION_OF_UNSAFE(x) (sizeof(x) / sizeof((x)[0]))
#define DIMENSION_OF_SAFER(x) (sizeof(x) / sizeof(0[(x)]))
int ints[4];
DIMENSION_OF_UNSAFE(ints); // 4
DIMENSION_OF_SAFER(ints); // 4
std::vector v(4);
DIMENSION_OF_UNSAFE(v); // gives impl-defined value; v likely wrong
DIMENSION_OF_SAFER(v); // does not compile
There's more to this, for dealing with pointers, but that requires some additional template smarts. Check out the implementation of STLSOFT_NUM_ELEMENTS()
in the STLSoft libraries, and read about it all in chapter 14 of Imperfect C++.
edit: some of the commenters suggest that the implementation does not reject pointers. It does (as well as user-defined types), as illustrated by the following program. You can verify this by uncommented lines 16 and 18. (I just did this on Mac/GCC4, and it rejects both forms).
#include <stlsoft/stlsoft.h>
#include <vector>
#include <stdio.h>
int main()
{
int ar[1];
int* p = ar;
std::vector<int> v(1);
printf("ar: %lu\n", STLSOFT_NUM_ELEMENTS(ar));
// printf("p: %lu\n", STLSOFT_NUM_ELEMENTS(p));
// printf("v: %lu\n", STLSOFT_NUM_ELEMENTS(v));
return 0;
}