Семантика символа []

Это время, когда этот пост открыт. Я удивлен, почему никто не думал о

public static final List<LanguageModel> GenderDataSource = new ArrayList<GenderModel>(){{
    add(new LanguageModel("0", "English"));
    add(new LanguageModel("1", "Hindi"));
    add(new LanguageModel("1", "Tamil"));
};};

, где LanguageModel просто содержит два свойства Id и Title или использует все, что ваш модельный класс общих Тип может быть.

Должен работать как постоянный.

- N Baua

14
задан user51568 30 January 2009 в 16:44
поделиться

6 ответов

Ну, &a случай должен быть очевидным. Вы берете адрес массива, точно как ожидалось. a является немного более тонким, но ответ - то, что a массив. И поскольку любой программист C знает, массивы имеют тенденцию ухудшиться в указатель в малейшей провокации, , например при передаче его как параметра функции.

Так scanf("%s", a) ожидает указатель, не массив, таким образом, массив ухудшается в указатель на первый элемент массива.

, Конечно scanf("%s", &a) работы также, потому что это - явно адрес массива.

Редактирование: ой, похож, мне полностью не удалось рассмотреть, какие типы аргумента scanf на самом деле ожидает. Оба случая приводят к указателю на тот же адрес, но различных типов. (указатель для обугливания, по сравнению с указателем на массив символов).

И я с удовольствием признаю, что не знаю достаточно о семантике для замещающего знака (...), которого я всегда избегал как чумы, так похож на преобразование в то, какой бы ни вводят scanf, заканчивает тем, что использовал, может быть неопределенное поведение. Прочитайте комментарии и ответ litb. Можно обычно доверять ему для разбираний в этом материале. ;)

18
ответ дан 1 December 2019 в 06:39
поделиться

Ну, scanf ожидает символ* указатель как следующий аргумент при наблюдении "%s". Но то, что Вы даете ему, является указателем на символ [100]. Вы даете его char(*)[100]. Это, как гарантируют, не будет работать вообще, потому что компилятор может использовать другое представление для указателей массива, конечно. При включении предупреждений для gcc Вы будете видеть также надлежащее отображенное предупреждение.

при обеспечении объекта аргумента, который является аргументом, не имеющим перечисленный параметр в функции (так, как в случае для scanf, когда имеет стиль vararg "..." аргументы после строки формата), массив ухудшится к указателю на его первый элемент. Таким образом, компилятор создаст char* и передача это к printf.

Так, никогда не делают это с &a и передают его scanf, использующему "%s". Хорошие компиляторы, как comeau, предупредят Вас правильно:

предупреждение: аргумент является несовместимым с соответствующим преобразованием строки формата

, Конечно, &a и (char*)a имеют тот же сохраненный адрес. Но это не означает, что можно использовать &a и (char*)a попеременно.

<час>

Некоторый Стандарт заключает в кавычки, чтобы особенно показать, как аргументы указателя не преобразованы в void* автоволшебно, и как все это - неопределенное поведение.

Кроме тех случаев, когда это - операнд sizeof оператора или унарного & оператор, или строковый литерал, используемый для инициализации массива, выражение, которое имеет тип ‘‘array type’’, преобразовывается в выражение с типом ‘‘pointer к type’’, который указывает на начальный элемент объекта массива. (6.3.2.1/3)

Так, который всегда делается - не упоминается ниже явно больше при слушании допустимых случаев, когда типы могут отличаться.

нотация замещающего знака в операторе объявления прототипа функции заставляет преобразование типа аргумента останавливаться после последнего заявленного параметра. Продвижения параметра по умолчанию выполняются на запаздывающих аргументах. (6.5.2.2/7)

О то, как va_arg ведет себя, извлекая аргументы, передало printf, который является функцией vararg, акцент, добавленный мной (7.15.1.1/2):

Каждый вызов va_arg макроса изменяет AP так, чтобы значения последовательных аргументов были возвращены в свою очередь. Тип параметра должен быть именем типа, указанным таким образом, что тип указателя на объект, который имеет указанный тип, может быть получен просто postп¬Ѓxing * для ввода. Если существует никакой фактический следующий аргумент, или если тип не совместим с типом фактического следующего аргумента (как продвинуто согласно продвижениям параметра по умолчанию), , поведение не определено , за исключением следующих случаев:

  • один тип является типом целого числа со знаком, другой тип является соответствующим типом беззнаковых целых чисел, и значение является представимым в обоих типах;
  • один тип , указатель для освобождения и другой является указателем на тип символов .

ну, вот, каково тот продвижение параметра по умолчанию :

, Если выражение, которое обозначает вызванную функцию, имеет тип, который не включает прототип, целочисленные продвижения выполняются на каждом аргументе, и аргументы, которые имеют плавание типа, продвинуты для удвоения. Их называют продвижениями параметра по умолчанию. (6.5.2.2/6)

11
ответ дан 1 December 2019 в 06:39
поделиться

Это было некоторое время, так как я запрограммировал в C, но здесь являюсь моим 2c:

char a[100] не выделяет отдельную переменную для адреса массива, таким образом, выделение памяти похоже на это:

 ---+-----+---
 ...|0..99|...
 ---+-----+---
    ^
    a == &a

Для сравнения, если массив был malloc'd затем, существует отдельная переменная для указателя, и a != &a.

char *a;
a = malloc(100);

В этом случае память похожа на это:

 ---+---+---+-----+---
 ...| a |...|0..99|...
 ---+---+---+-----+---
    ^       ^
    &a  !=  a

K& R 2-й Ed. p.99 описывает это довольно хорошо:

корреспонденция между индексацией и адресной арифметикой с указателями очень близка. По определению значение переменной или выражение массива типа являются адресом нуля элемента массива. Таким образом после присвоения pa=&a[0]; pa и a имеют идентичные значения. Так как название массива является синонимом для местоположения начального элемента, присвоение pa=&a[0] может также быть записано как pa=a;

6
ответ дан 1 December 2019 в 06:39
поделиться

Массив C может быть неявно преобразован в указатель на свой первый элемент (C99:TC3 6.3.2.1 В§3), т.е. существует много случаев, где a (который имеет тип char [100]) будет вести себя тот же путь как &a[0] (который имеет тип char *). Это объясняет, почему, передавая a, поскольку аргумент будет работать.

, Но не начинают думать, что это будет всегда иметь место: существуют важные различия между массивами и указателями, например, относительно присвоения, sizeof и независимо от того, что я не могу думать прямо сейчас...

&a на самом деле одна из этих ловушек: Это создаст указатель на массив, т.е. он имеет тип char (*) [100] не char **). Это означает &a, и &a[0] укажет на ту же ячейку памяти, но будет иметь различные типы.

Насколько я знаю, нет никакого неявного преобразования между этими типами, и они, как гарантируют, не будут иметь совместимое представление также. Все, что я мог найти, является C99:TC3 6.2.5 В§27, который не делает говорит многое об указателях на массивы:

[...] Указатели на другие типы не должны иметь того же представления или требований выравнивания.

, Но существует также 6.3.2.3 В§7:

[...], Когда указатель на объект преобразовывается в указатель на тип символов, результат указывает на самый низкий обращенный байт объекта. Последовательные инкременты результата, до размера объекта, приводят к указателям на остающиеся байты объекта.

, Таким образом, бросок (char *)&a должен работать как ожидалось. На самом деле я предполагаю здесь, что самый низкий обращенный байт массива будет самым низким обращенным байтом своего первого элемента - не уверенный, если это будет гарантироваться, или если бы компилятор является бесплатным добавить произвольное дополнение перед массивом, но если так, который был бы серьезно странным...

Так или иначе, чтобы это работало, &a все еще, должен быть брошен к [1 113] (или void * - стандарт гарантирует, что эти типы имеют совместимые представления). Проблема состоит в том, что не будет никаких преобразований, относился к аргументам переменной кроме продвижения параметра по умолчанию, т.е. необходимо сделать бросок явно сами.

<час>

Для суммирования:

&a имеет тип char (*) [100], который мог бы иметь другое разрядное представление, чем [1 117]. Поэтому явный бросок должен быть сделан программистом, потому что для аргументов переменной, компилятор не может знать, в какой он должен преобразовать значение. Это означает, что только продвижение параметра по умолчанию будет сделано, который, как [1 125] litb, на который указывают, не включает преобразование в [1 118]. Из этого следует, что:

  • scanf("%s", a); - хороший
  • scanf("%s", &a); - плохо
  • scanf("%s", (char *)&a); - должен быть в порядке
5
ответ дан 1 December 2019 в 06:39
поделиться

char [100] составной тип 100 смежных char, чей sizeof равняется 100.

Являющийся литым к указателю ((void*) a), эта переменная приводит к адресу первого char.

Ссылка на переменную этого типа (&a) приводит к адресу целой переменной, которая, в свою очередь, также, оказывается, адрес первого char

0
ответ дан 1 December 2019 в 06:39
поделиться

Извините, крошечный бит вне темы:

Это напомнило мне о статье, что я читал приблизительно 8 лет назад, когда я кодировал полный рабочий день C. Я не могу найти статью, но я думаю, что она была названа "массивы, не указатели" или что-то как этот. Так или иначе я действительно сталкивался с этим массивы C и указатели FAQ , который является интересным чтением.

4
ответ дан 1 December 2019 в 06:39
поделиться