LINUX.ORG.RU

[C++] почему?

 


0

0
void f(const int[3]);

...

f({1, 2, 3});

почему так нельзя? при том, что вот так:

const int a[3] = {1, 2, 3};

f(a);

вполне себе законно. {} - это, вроде бы, конструктор для const T[]; конструкторы в вызове функции использовать вполне себе можно. основание для такого особого отношения есть вообще?

это всё при том, что:

void g(const char[3]);

...

g("123");

замечательно работает. C-style строка в C++ - она, в общем-то, массив символов - два исключения из общих языковых правил в одном выражении

ну и то, что и в f и в g можно с лёгкостью передавать массивы большего размера, чем указано в сигнатуре, тоже как-то нехорошо. приведение T[] к T* это, конечно, не так уж и плохо - но толку тогда от такой сигнатуры, спрашивается, если компилятор (с -Wall -pedantic) даже предупреждения не выдаёт?

★★★★★
Ответ на: комментарий от jtootf

>про f((int[3]){1, 2, 3})

тут тип известен. хотя насколько это соответствует стандарту, судить не берусь.

anonymous
()
Ответ на: комментарий от Absurd

>>Взять адрес у несуществующего массива реально трудно.

> Он вполне себе существует в рантайме в секции .const вместе с другими литералами.


Нет гарантии существования литерных констант в рантайме.

int a;
a = a + 1;

"1" - литерная константа, но ни в сеции .const, ни где бы то нибыло еще ее может не оказаться. Достаточно очевидно, что взять адрес у литерной константы на этапе компиляции нельзя, и добавленный воркэраунд для "string literal" не отменяет этого общего правила.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

> int a;
> a = a + 1;


Подразумевается

int a;
...
a = a + 1;

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>добавленный воркэраунд для "string literal" не отменяет этого общего правила

чем этот воркэраунд не подходит для общего случая?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>добавленный воркэраунд для "string literal" не отменяет этого общего правила.

с чего он стал "воркэраунд"? ведь в этом случае указатель в рантайме передают( а не само значение), который должен указывать на объект.

anonymous
()
Ответ на: комментарий от LamerOk

>Вопросы к Д. Ритчи.

ну вот, чуть что так сразу к Ритчи; неужели на ЛОРе не хватит аналитиков, чтобы ответить на этот вопрос?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от anonymous

С того, что этот синтаксис ортогонален синтаксису любых других константных литералов во время компиляиции и введен с единственной целью - не превращать объявление обычных строк в священную процедуру с бубуном. И, сделав это исключение, всё таки напоролись на грабли с const, приведенные выше.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>не превращать объявление обычных строк в священную процедуру с бубуном

несправедливость же - для всех остальных составных литералов бубен остался

jtootf ★★★★★
() автор топика

ко второму вопросу

void g(const char a[3])
{
    std::cout << "sizeof a = " << sizeof(a) << "\n";
    std::cout << "strlen(a) = " << strlen(a) << std::endl;
}

...

g("123456");
sizeof a = 4
strlen(a) = 6

и у нас как бы функция типа void (const char[3]), которая на самом деле получает ни разу не const char[3]. -Wall -pedantic, ни одного предупреждения

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>И, сделав это исключение, всё таки напоролись на грабли с const, приведенные выше.

какие грабли из-за строковых литералов тебе померещились?

>С того, что этот синтаксис ортогонален синтаксису любых других константных литералов во время компиляиции

это что-то не бред больше похоже.

anonymous
()
Ответ на: комментарий от jtootf

> и у нас как бы функция типа void (const char[3]), которая на самом деле получает ни разу не const char[3].

Может ты наконец поймешь разницу между указателем и массивом?

LamerOk ★★★★★
()

> void f(const int[3]);

void f(int[const 3]);

в С99 такая запись.

dilmah ★★★★★
()
Ответ на: комментарий от jtootf

>и у нас как бы функция типа void (const char[3]), которая на самом деле получает ни разу не const char[3]. -Wall -pedantic, ни одного предупреждения

и что тебе удивило? что есть размер указателя? что же ещё можно ожидать от фаната с мозгами промытыми микрософт хаскел(тм).

anonymous
()
Ответ на: комментарий от anonymous

> какие грабли из-за строковых литералов тебе померещились?

Тебе не понятна разница междуо объявлениями
char *t;
и
const char *t;

?

> это что-то не бред больше похоже.


Хороший способ сказать "я не понял ответа" )))

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>Может ты наконец поймешь разницу между указателем и массивом?

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

jtootf ★★★★★
() автор топика
Ответ на: комментарий от anonymous

>и что тебе удивило? что есть размер указателя?

отсутствие предупреждений во время компиляции. преобразование константного массива к указателю - не проблема, а вот обратное (с заменой размерности) уже, мягко говоря, чревато проблемами

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

>Тебе не понятна разница междуо объявлениями

Строковые литералы являются константами.

anonymous
()
Ответ на: комментарий от anonymous

С какого года? Грабли, о которых я говорил, - необходимость менять тип указателя, котороый можно инициализировать стринговой литерной константой.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

> Тип char[] идентичен типу char*

Ламер ты и есть. Злокачественный.

tailgunner ★★★★★
()
Ответ на: комментарий от jtootf

>преобразование константного массива к указателю - не проблема, а вот обратное (с заменой размерности) уже, мягко говоря, чревато проблемами

we’re still screwing around with ’70s debuggers and linkers, and it’s stupid. I don’t know why we put up with it. (C) Brendan Eich

Absurd ★★★
()
Ответ на: комментарий от LamerOk

>Грабли, о которых я говорил, - необходимость менять тип указателя, котороый можно инициализировать стринговой литерной константой.

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

anonymous
()
Ответ на: комментарий от LamerOk

>Тип char[] идентичен типу char* Это разная запись одной и той же семантической конструкции.

Нифига- char[] - массив, char* - указатель. Ничего общего, разве что а) У параметров функций - массивов срезается первая размерность и замещается указателем и б) при передаче массива в функцию делается автокаст массив->указатель.

Absurd ★★★
()
Ответ на: комментарий от LamerOk

> Тип char[] идентичен типу char*

рукалицо.жпг

ntp
()
Ответ на: комментарий от Absurd

> Нифига- char[] - массив, char* - указатель. Ничего общего, разве что
... б) при передаче массива в функцию делается автокаст массив->указатель.

Это и имеется в виду. А не то, о чём вы все подумали, грязные извращенцы.

LamerOk ★★★★★
()
Ответ на: комментарий от anonymous

> что-то вроде того,

Что то вроде того, что синтаксис языка _ПРИШЛОСЬ МЕНЯТЬ_, блджад.

LamerOk ★★★★★
()
Ответ на: комментарий от golodranez

ты не можешь передать в функцию массив

template <typename T, size_t n>
size_t size(T (&)[n])
{
	return n;
}

у меня этот пример скоро уже в печёнках будет

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

Тип char[] идентичен типу char* Это разная запись одной и той же семантической конструкции.

все милостиво над тобой поулыбались

теперь к сути вопроса:

void f(const int a[3])
{
	std::cout << "f. sizeof a = " << sizeof(a) << std::endl;
}

void g()
{
	const int a[3] = {1, 2, 3};

	std::cout << "g. sizeof a = " << sizeof(a) << std::endl;

	f(a);
}

результат где-то такой:

g. sizeof a = 12
f. sizeof a = 4

в функции g есть локальная переменная типа int[3], в функции f есть локальная переменная типа int[3]. тип одинаковый, результат выполнения sizeof - разный. преобразование было произведено подкапотно, без лексически наблюдаемого описания, без предупреждения

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

> все милостиво над тобой поулыбались

Все, кроме тебя, вспомнили про разницу между типом переменной и типом выражения. А вот ты, судя по

> в функции g есть локальная переменная типа int[3], в функции f есть локальная переменная типа int[3].


её так и не понял.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>разницу между типом переменной и типом выражения

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

jtootf ★★★★★
() автор топика
Ответ на: комментарий от Absurd
template<size_t size>
void ft(const int (&)[size]);

template<>
void ft(const int (&)[3])
{
	std::cout << "ft. sizeof a = 3, fixed" << std::endl;
}

такой вариант работает, но падает совсем не так хорошо, как хотелось бы

jtootf ★★★★★
() автор топика
Ответ на: комментарий от LamerOk

блин, я не разу не "сиплюсплюсник", но блин до боли в глазах и гула в голове не могу понять: где в примере переменная, а где выражение?

yyk ★★★★★
()
Ответ на: комментарий от yyk

Чего ж тут непонятного? Ты видишь здесь объявление массива?

void f(const int a[3])
{
   std::cout << "f. sizeof a = " << sizeof(a) << std::endl;
}
LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>Ты видишь здесь объявление массива?

const int a[3]. локальная переменная функции f, имеет имя a и тип int[3]

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>в функции f есть локальная переменная типа int[3]. тип одинаковый, результат выполнения sizeof - разный.

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

anonymous
()
Ответ на: комментарий от anonymous

а ничего, что sizeof в рантайме

тебя ждёт много удивительных открытий. sizeof - compile-time операция

template <size_t n>
int test()
{
	return n;
}

...

test<sizeof(char)>();

компилируется и работает на ура

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>template <typename T, size_t n>
size_t size(T (&)[n])
{
return n;
}

И что? Ты не передашь массив в функцию. Ты как вообще догадался объявлять функцию как f(some_type[amount]) ?

golodranez ★★★★
()
Ответ на: комментарий от jtootf

>sizeof - compile-time операция

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

anonymous
()
Ответ на: комментарий от golodranez

И что? Ты не передашь массив в функцию.

*икнул* а что же я делаю?

template <typename T, size_t n>
void print(T (&a)[n])
{
	for(int i = 0; i < n; ++i)
	{
		std::cout << "a[" << i << "] = " << a[i] << std::endl;
	}
}

вроде передаётся

Ты как вообще догадался объявлять функцию как f(some_type[amount]) ?

потребовалось для подсчёта количества элементов сишного массива. sizeof(arr)/sizeof(elem) в таком случае не работает - благодаря всё тому же неявному преобразованию к типу указателя

jtootf ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

это что за поток сознания? не распарсил

jtootf ★★★★★
() автор топика
Ответ на: комментарий от Absurd
template <bool> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> {};

template<size_t size>
void ft(const int (&)[size])
{
	STATIC_ASSERTION_FAILURE<false>();
}

template<>
void ft(const int (&)[3])
{
	std::cout << "ft. sizeof a = 3, fixed" << std::endl;
}

а вот такой вариант, наконец-то, падает в компайл-тайм. и даже сообщение об ошибке можно прикрутить более-менее вменяемое

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

> const int a[3]. локальная переменная функции f, имеет имя a и тип int[3]

Ты не увиливай, а отвечай на прямо поставленный вопрос - здесь есть объявление массива или нет?

LamerOk ★★★★★
()
Ответ на: комментарий от jtootf

>это что за поток сознания?

так и запишем: автор не осилил, но осуждает.

anonymous
()
Ответ на: комментарий от jtootf

>а вот такой вариант, наконец-то, падает в компайл-тайм.

Это фейл. Функция ft должна быть в .c++ файле и оно должно падать в линк-тайм.

Absurd ★★★
()
Ответ на: комментарий от LamerOk

для человека, сказавшего правильно и по существу на весь тред всего пару фраз, ты удивительно надоедлив. да, здесь есть объявление массива

jtootf ★★★★★
() автор топика
Ответ на: комментарий от Absurd

>Это фейл

почему?

>Функция ft должна быть в .c++ файле и оно должно падать в линк-тайм.

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

jtootf ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.