Добавьте привязку к свойству selected
, например:
<option *ngFor="#workout of workouts" [selected]="workout.name == 'back'">{{workout.name}}</option>
Значение, возвращаемое sizeof
, будет иметь тип size_t
.
Обычно он используется в качестве количества элементов в массиве, потому что он будет иметь достаточный размер. size_t
всегда без знака, но это определяется реализацией, какой это тип. Наконец, определяется реализацией, может ли реализация поддерживать объекты размером даже SIZE_MAX
байтов ... или даже близко к нему.
size_t
рассматривается как тип для использования, несмотря на то, что он не был официально ратифицирован ни стандартами C, ни C ++.
Основанием для этого является то, что sizeof(values)
будет такого типа (что соответствует в соответствии со стандартами C и C ++), и число элементов обязательно будет не больше этого, поскольку sizeof
] для объекта не менее 1.
Похоже, что при размере массива не может превышать размер
blockquote>unsigned int
.Это, кажется, имеет место в вашей конкретной реализации C [++] .
Я прав? Является ли это специфичным для gcc или является частью какого-либо стандарта C или C ++?
blockquote>Он не является характеристикой GCC в целом и не определяется ни стандартом C, ни C ++. Это характерная черта вашей конкретной реализации : версия GCC для вашей конкретной вычислительной платформы.
Стандарт C требует, чтобы выражение, обозначающее количество элементов массива, имело целочисленный тип, но оно не указывает конкретный тип. Мне кажется странным, что ваш GCC, кажется, утверждает, что он предоставляет вам массив с другим количеством элементов, чем вы указали. Я не думаю, что это соответствует стандарту, и я не думаю, что это имеет смысл как расширение. Я бы предпочел, чтобы вместо этого он отклонял код.
В вашей реализации size_t
определяется как unsigned int
, а uint32_t
определяется как long unsigned int
. Когда вы создаете массив C, аргумент для размера массива неявно преобразуется компилятором в size_t
.
Вот почему вы получаете предупреждение. Вы задаете аргумент размера массива с помощью uint32_t
, который преобразуется в size_t
, и эти типы не совпадают.
size_t
.
[Этот ответ был написан, когда вопрос был помечен C и C ++. Я еще не рассмотрел его в свете того, что OP использует C ++ вместо C.]
size_t
- это тип, который стандарт C обозначает для работы с размерами объектов. Тем не менее, это не панацея для получения правильных размеров.
size_t
должно быть определено в заголовке <stddef.h>
(а также в других заголовках).
Стандарт C не требует, чтобы выражения для размеров массива, если они указаны в объявлениях, имели тип size_t
, и при этом он не требует, чтобы они помещались в size_t
. Не указано, что должна делать реализация C, когда она не может удовлетворить запрос на размер массива, особенно для массивов переменной длины.
В вашем коде:
const uint32_t N = 65537;
uint8_t values[N];
values
объявлен как массив переменной длины. (Хотя мы видим, что значение N
можно легко узнать во время компиляции, оно не соответствует определению константного выражения в C, поэтому uint8_t values[N];
квалифицируется как объявление массива переменной длины.) Как вы заметили, GCC предупреждает, что 32-разрядное целое число без знака N
сужается до 16-разрядного целого числа без знака. Это предупреждение не требуется стандартом C; это любезно предоставлено компилятором. Более того, преобразование вообще не требуется - поскольку стандарт C не определяет тип для измерения массива, компилятор может принять любое целочисленное выражение здесь. Поэтому тот факт, что он вставил неявное преобразование в тип, который ему необходим для измерений массива, и предупредил вас об этом, является особенностью компилятора, а не стандарта Си.
Подумайте, что произойдет, если вы напишите:
size_t N = 65537;
uint8_t values[N];
Теперь в uint8_t values[N];
не будет предупреждений, поскольку 16-разрядное целое число (ширина size_t
в вашей реализации C) используется там, где необходимо 16-битное целое число. Однако в этом случае ваш компилятор, вероятно, предупреждает в size_t N = 65537;
, так как 65537
будет иметь 32-битный целочисленный тип, и сужающее преобразование выполняется во время инициализации N
.
Однако тот факт, что вы используете массив переменной длины, предполагает, что вы можете вычислять размеры массива во время выполнения, и это только упрощенный пример. Возможно, ваш реальный код не использует постоянные размеры, как это; это может вычислить размеры во время выполнения. Например, вы можете использовать:
size_t N = NumberOfGroups * ElementsPerGroup + Header;
В этом случае есть вероятность, что будет рассчитан неправильный результат. Если все переменные имеют тип size_t
, результат может легко переноситься (эффективно выходя за пределы типа size_t
). В этом случае компилятор не будет предупреждать вас, потому что значения имеют одинаковую ширину; нет сужающего преобразования, только переполнение.
Следовательно, использование size_t
недостаточно для защиты от ошибок в размерах массива.
Альтернативой является использование типа, который, как вы ожидаете, будет достаточно широким для ваших вычислений, возможно uint32_t
. Учитывая NumberOfGroups
и такие как uint32_t
типы, тогда:
const uint32_t N = NumberOfGroups * ElementsPerGroup + Header;
будет давать правильное значение для N
. Затем вы можете проверить его во время выполнения, чтобы защититься от ошибок:
if ((size_t) N != N)
Report error…
uint8_t values[(size_t) N];
Я расскажу об этой проблеме с правилами в «неполном и неполном» проекте стандарта ISO CPP n4659 . Акцент добавлен мной.
11.3.4 определяет объявления массива. Первый абзац содержит
Если присутствует константное выражение [в квадратных скобках] (8.20), оно должно быть преобразованным константным выражением типа std :: size_t [. ..].
blockquote>
std::size_t
из<cstddef>
и определено как[...] определяемый реализацией целочисленный тип без знака, который является достаточно большим, чтобы содержать размер в байтах любой объект.
blockquote>Поскольку он импортируется через заголовки стандартной библиотеки C, стандарт C имеет отношение к свойствам из
size_t
. Проект ISO C N2176 предписывает в 7.20.3 «минимальные максимумы», если хотите, целочисленных типов. Дляsize_t
этот максимум составляет 65535. Другими словами, 16-битныйsize_t
полностью соответствует.«Преобразованное константное выражение» определено в 8.20 / 4:
Преобразованное константное выражение типа T является выражением, неявно преобразованным в тип T, где преобразованное выражение является константным выражением, и неявная последовательность преобразования содержит только [любое из 10 различных преобразований, одно из которых касается целых чисел (пар. 4.7):]
- целочисленные преобразования (7.8) , кроме сужения преобразования (11.6.4)
blockquote>Интегральное преобразование (в отличие от повышения , которое изменяет тип на эквивалентные или более крупные типы) определяется следующим образом (7.8 / 3):
Prvalue целочисленного типа может быть преобразовано в prvalue другого целочисленного типа.
blockquote>7.8 / 5 затем исключает интегральные продвижения из интегральных преобразований. Это означает, что преобразования обычно сужают изменения типа.
Сужающие преобразования (которые, как вы помните, исключены из списка разрешенных преобразований в преобразованных константных выражениях , используемых для размеров массивов), определены в контексте списка -инициализация, 11.6.4, пар. 7
Сужающее преобразование - это неявное преобразование
blockquote>
[...]
7.3 1 sup> - из целочисленного типа [. ..] к целочисленному типу, который не может представлять все значения исходного типа, за исключением случаев, когда источником является константное выражение, значение которого после интегральных повышений будет соответствовать целевому типу.Это фактически говорит о том, что эффективный размер массива должен быть постоянным значением при отображении, что является вполне разумным требованием для избежания неожиданностей.
А теперь давайте сделаем это вместе. Рабочая гипотеза состоит в том, чтоstd::size_t
представляет собой 16-битный целочисленный тип без знака со значением в диапазоне 0,65535. Целочисленный литерал65537
не представлен в 16-битной системеunsigned int
и поэтому имеет типlong
. Поэтому он будет подвергаться целочисленному преобразованию. Это будет сужающее преобразование , потому что значение не представляется в 16-битномsize_t
2 sup>, так что условие исключения в 11.6.4 / 7.3, "значение подходит в любом случае ", не применяется.Итак, что это значит?
11.6.4 / 3.11 - это универсальное правило для сбоя при создании значения инициализатора из элемента в списке инициализатора. Поскольку правила списков инициализаторов используются для размеров массивов, мы можем предположить, что универсальное условие сбоя преобразования применяется к константе размера массива:
(3.11) - В противном случае программа плохо сформирован.
blockquote>Для создания диагностики требуется соответствующий компилятор, что он и делает. Дело закрыто.
1 sup> Да, они подразделяют абзацы.2 sup> Преобразование целочисленного значения 65537 (в любом типе, который может содержать число & mdash; здесь, вероятно, `long) в 16-битовое целое число без знака является определенной операцией. 7,8 / 2 подробностей:
Если тип назначения не имеет знака, полученное значение будет являться целочисленным наименьшим числом без знака, совпадающим с целым числом источника (по модулю 2 n sup) > где n - количество битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). - конец примечания]
blockquote>Двоичное представление 65537 равно
1_0000_0000_0000_0001
, то есть установлен только младший значащий бит из младших 16 битов. Преобразование в 16-битное значение без знака (которое указывает косвенное свидетельствоsize_t
) вычисляет [значение выражения] по модулю 2 ^ 16, т. Е. Просто принимает младшие 16 бит. Это приводит к значению 1, указанному в диагностике компилятора.