Представляет собой массив С++ размера N отдельного типа

я думал так

int a1[5];

и

int a2[6];

были отдельными типами.

Но

void foo(int a[5]){};
void foo(int a[6]){};

не будет компилироваться, говоря, что это дублированные определения foo (т.е. foo(int *a))

Я был очень удивлен этим. Одна из причин, почему VLA не разрешены в стандарте C++, заключается в том, что они нарушают систему типов.

Я также был удивлен, обнаружив, что c делает то же самое.

void foo(int a[4]){
   printf("sz=%ld", sizeof(a));
}

сообщает размер указателя. Я ожидал, что он сообщит 4*sizeof(int) (и примет только переменную типа int[4], которая будет принята в качестве аргумента вызова)

Мне нужно проверить, но я думаю, что вы просто сталкиваетесь с обычным старым преобразованием указателя массива.

David C. Rankin 19.09.2023 05:20

Ну, да. a — указатель. Массивы в аргументах — это просто указатели. Это имеет место как в C, так и в C++.

Etienne de Martel 19.09.2023 05:20

в C/C++, когда вы передаете массив функции, вы получаете только указатель на 0-й индекс массива, обойти его невозможно, поэтому многие функции в C/C++ принимают массив и массив sizeof при каждом вызове возможно, вы захотите посмотреть это видео youtube.com/watch?v=GaclhRKfxtI

X-_-FARZA_ D-_-X 19.09.2023 05:21

@pm100, int a[5] как параметр функции имеет тот же тип, что и int *a. Как и int a[6]. Это не проблема с массивом, указывающим на первый элемент, а проблема языка, связанная с объявлениями функций.

chux - Reinstate Monica 19.09.2023 05:21

Если вам нужен настоящий массив, вам нужно передать его по ссылке (void foo(int (&a)[5]){})

Etienne de Martel 19.09.2023 05:22

@pm100 printf("sz=%ld", sizeof(a)); лучше как printf("sz=%zu", sizeof(a));, чтобы избежать проблем с боковой панелью из-за использования неправильного спецификатора.

chux - Reinstate Monica 19.09.2023 05:24

Я думаю, это одна из причин использования std::array: разные размеры являются разными типами.

pm100 19.09.2023 05:30

@EtiennedeMartel - Хорошо, теперь я понимаю, что объявление функции arg как int[5] — это то же самое, что и int * (что для меня неожиданно). Но отличаются ли int[5] и int[6] в других отношениях?

pm100 19.09.2023 05:32

@pm100 Да. Аргументы функций особенные — и в C, и в C++ (некоторые могут сказать, что это аномалия языка, но это так). Существуют и другие контексты, в которых int[5] и int [6] относятся к разным типам. например int x[5]; int (&r)[5] = x; int (*p)[5] = &x; действителен (и определяет r и p соответственно как ссылку и указатель на массив из 5 int), но int x[6]; int (&r)[5] = x; int (*p)[5] = &x имеет две диагностируемые ошибки (поскольку ни ссылка, ни указатель на массив из 5 элементов не могут ссылаться/указывать на массив из 6 элементов).

Peter 19.09.2023 05:55

Типы int[5] и int[6] различны, а типы void(int[5]), void(int[6]) и void(int*) из-за распада массива одинаковы.

tstanisl 19.09.2023 05:56

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

Chris Dodd 19.09.2023 07:24

Полностью избегайте этой проблемы, просто забывая о существовании массивов в стиле C и вместо этого используйте std::array или std::vector.

Jesper Juhl 19.09.2023 15:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
103
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, это разные типы, это можно подтвердить:

int a[5];
int b[6];
static_assert(!std::is_same_v<decltype(a), decltype(b)>);

Ваша проблема в том, что в списках параметров функций массивы молча заменяются указателями, поэтому и void foo(int a[5]), и void foo(int a[6]) в конечном итоге становятся void foo(int *a).

Это (замена типа массива указателем) происходит только с реальными массивами, в отличие, например, от ссылки на массивы, поэтому void foo(int (&a)[5]) будет работать (или int (*a)[5] в C).

различны ли они в c, есть ли способ показать это?

pm100 19.09.2023 05:53

@pm100 sizeof будут разными, что AFAIK означает, что они не могут быть одного типа.

NathanOliver 19.09.2023 06:00

@pm100 int x[5]; int (*p)[6] = &x не будет компилироваться, поскольку x — это массив из пяти элементов, а p — указатель на массив из 6 элементов. Это верно как для C, так и для C++. Кроме того, sizeof(int [5]) и sizeof(int[6]) будут давать разные значения на обоих языках (а sizeof(int *) — это еще одно значение, которое, вероятно, не будет равно ни одному из них)

Peter 19.09.2023 06:00

Типы функций аналогичным образом заменяются указателями, когда вы используете их в качестве типов аргументов в объявлении, так что это не просто типы массивов.

Chris Dodd 19.09.2023 07:26

Любопытство в этой теме заключается в том, что объект массива может иметь другой объявленный тип в одной точке, скажем, в одной единице перевода (TU; в этот момент его тип является неполным), а в другой единице трансляции может быть полным и иметь другой объявленный тип. , то есть int a[] в TU #1 имеет другой тип, чем int a[5] в TU #2. Добавление еще одного определения int a[7] в ТУ №3 — это UB через нарушение ODR. Объекты-массивы — одни из немногих объектов, которые могут иметь разные типы в разных контекстах.

dfrib 19.09.2023 13:40

Re «Это происходит только с массивами»: я думаю, вы имеете в виду, что это происходит с параметрами, которые напрямую объявлены как массивы, а не с массивами, вложенными в объявление параметра. Однако, как уже говорилось, это происходит не только с массивами. Параметр, объявленный как функция, также будет преобразован в параметр, который является указателем на функцию.

Eric Postpischil 19.09.2023 14:43

@EricPostpischil Под «этим» я имел в виду замену массива указателем. Теперь должно звучать лучше.

HolyBlackCat 19.09.2023 14:49

Другие вопросы по теме