Какой тип используется в C ++ для определения размера массива?

Добавьте привязку к свойству selected, например:

<option *ngFor="#workout of workouts" [selected]="workout.name == 'back'">{{workout.name}}</option>
8
задан Eric Postpischil 17 January 2019 в 01:19
поделиться

6 ответов

Значение, возвращаемое sizeof, будет иметь тип size_t.

Обычно он используется в качестве количества элементов в массиве, потому что он будет иметь достаточный размер. size_t всегда без знака, но это определяется реализацией, какой это тип. Наконец, определяется реализацией, может ли реализация поддерживать объекты размером даже SIZE_MAX байтов ... или даже близко к нему.

0
ответ дан Antti Haapala 17 January 2019 в 01:19
поделиться

size_t рассматривается как тип для использования, несмотря на то, что он не был официально ратифицирован ни стандартами C, ни C ++.

Основанием для этого является то, что sizeof(values) будет такого типа (что соответствует в соответствии со стандартами C и C ++), и число элементов обязательно будет не больше этого, поскольку sizeof ] для объекта не менее 1.

0
ответ дан Bathsheba 17 January 2019 в 01:19
поделиться

Похоже, что при размере массива не может превышать размер unsigned int.

Это, кажется, имеет место в вашей конкретной реализации C [++] .

Я прав? Является ли это специфичным для gcc или является частью какого-либо стандарта C или C ++?

Он не является характеристикой GCC в целом и не определяется ни стандартом C, ни C ++. Это характерная черта вашей конкретной реализации : версия GCC для вашей конкретной вычислительной платформы.

Стандарт C требует, чтобы выражение, обозначающее количество элементов массива, имело целочисленный тип, но оно не указывает конкретный тип. Мне кажется странным, что ваш GCC, кажется, утверждает, что он предоставляет вам массив с другим количеством элементов, чем вы указали. Я не думаю, что это соответствует стандарту, и я не думаю, что это имеет смысл как расширение. Я бы предпочел, чтобы вместо этого он отклонял код.

0
ответ дан John Bollinger 17 January 2019 в 01:19
поделиться

В вашей реализации size_t определяется как unsigned int, а uint32_t определяется как long unsigned int. Когда вы создаете массив C, аргумент для размера массива неявно преобразуется компилятором в size_t.

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

1110 Это, вероятно, не то, что вы хотите. Вместо этого используйте size_t.

0
ответ дан vlind 17 January 2019 в 01:19
поделиться

[Этот ответ был написан, когда вопрос был помечен 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];
0
ответ дан Eric Postpischil 17 January 2019 в 01:19
поделиться

Я расскажу об этой проблеме с правилами в «неполном и неполном» проекте стандарта ISO CPP n4659 . Акцент добавлен мной.

11.3.4 определяет объявления массива. Первый абзац содержит

Если присутствует константное выражение [в квадратных скобках] (8.20), оно должно быть преобразованным константным выражением типа std :: size_t [. ..].

std::size_t из <cstddef> и определено как

[...] определяемый реализацией целочисленный тип без знака, который является достаточно большим, чтобы содержать размер в байтах любой объект.

Поскольку он импортируется через заголовки стандартной библиотеки 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)

Интегральное преобразование (в отличие от повышения , которое изменяет тип на эквивалентные или более крупные типы) определяется следующим образом (7.8 / 3):

Prvalue целочисленного типа может быть преобразовано в prvalue другого целочисленного типа.

7.8 / 5 затем исключает интегральные продвижения из интегральных преобразований. Это означает, что преобразования обычно сужают изменения типа.

Сужающие преобразования (которые, как вы помните, исключены из списка разрешенных преобразований в преобразованных константных выражениях , используемых для размеров массивов), определены в контексте списка -инициализация, 11.6.4, пар. 7

Сужающее преобразование - это неявное преобразование
[...]
7.3 1 - из целочисленного типа [. ..] к целочисленному типу, который не может представлять все значения исходного типа, за исключением случаев, когда источником является константное выражение, значение которого после интегральных повышений будет соответствовать целевому типу.

Это фактически говорит о том, что эффективный размер массива должен быть постоянным значением при отображении, что является вполне разумным требованием для избежания неожиданностей.


А теперь давайте сделаем это вместе. Рабочая гипотеза состоит в том, что std::size_t представляет собой 16-битный целочисленный тип без знака со значением в диапазоне 0,65535. Целочисленный литерал 65537 не представлен в 16-битной системе unsigned int и поэтому имеет тип long. Поэтому он будет подвергаться целочисленному преобразованию. Это будет сужающее преобразование , потому что значение не представляется в 16-битном size_t 2 , так что условие исключения в 11.6.4 / 7.3, "значение подходит в любом случае ", не применяется.

Итак, что это значит?

11.6.4 / 3.11 - это универсальное правило для сбоя при создании значения инициализатора из элемента в списке инициализатора. Поскольку правила списков инициализаторов используются для размеров массивов, мы можем предположить, что универсальное условие сбоя преобразования применяется к константе размера массива:

(3.11) - В противном случае программа плохо сформирован.

Для создания диагностики требуется соответствующий компилятор, что он и делает. Дело закрыто.


1 Да, они подразделяют абзацы.

2 Преобразование целочисленного значения 65537 (в любом типе, который может содержать число & mdash; здесь, вероятно, `long) в 16-битовое целое число без знака является определенной операцией. 7,8 / 2 подробностей:

Если тип назначения не имеет знака, полученное значение будет являться целочисленным наименьшим числом без знака, совпадающим с целым числом источника (по модулю 2 n где n - количество битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). - конец примечания]

Двоичное представление 65537 равно 1_0000_0000_0000_0001, то есть установлен только младший значащий бит из младших 16 битов. Преобразование в 16-битное значение без знака (которое указывает косвенное свидетельство size_t) вычисляет [значение выражения] по модулю 2 ^ 16, т. Е. Просто принимает младшие 16 бит. Это приводит к значению 1, указанному в диагностике компилятора.

0
ответ дан Peter A. Schneider 17 January 2019 в 01:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: