LINUX.ORG.RU

C++ арифметика указателей: является ли код эквивалентным?

 , ,


1

2

Первый второму?

#include <iostream>
#include <cstddef>
#include <new>

int main()
{
    alignas(float) std::byte stor[3*sizeof(float)];
    
    for (int i = 0; i < 3; ++i)
        new (stor + i*sizeof(float)) float(i);
    
    for (int i = 0; i < 3; ++i)
        std::cout << *std::launder( reinterpret_cast<float*>(stor + i*sizeof(float)) ) << std::endl;
}
#include <iostream>
#include <cstddef>

int main()
{
    alignas(float) std::byte stor[3*sizeof(float)];
    
    for (int i = 0; i < 3; ++i)
        new (stor + i*sizeof(float)) float(i);
    
    for (int i = 0; i < 3; ++i)
        std::cout << ((float*)stor)[i] << std::endl;
}


Последнее исправление: sostupid (всего исправлений: 2)
Ответ на: комментарий от anonymous

бросайте этого тролля

Да вот тоже всё больше и больше склоняюсь к тому, что это тролинг. Хотя полной уверенности пока нет. Вдруг он действительно что-то не понимает и хочет разобраться?

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

тот кто хочет разобраться, тот берет и разбирается
молодые люди окончившие школу, или тем более ВУЗ должны способны к самостоятельному анализу и разбору
если они на это не способны, значит им нужно закончить школу, либо повторно пойти учится, форумы это не то место которые должны заменять эти два жизненных института(школу, ВУЗ)

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

Ты модифицировал элемент массива, а не объект

Т.е, по-твоему, после a[0] = 0; массив не изменился???

который является константным указателем на 0-й элемент.

При чём тут какие-то константные указатели????

в стандарте есть то, о чём ты говорил, что его нет.

И по прежнему говорю, что нет. Нет обоснования всей цепочки преобразований.

Т. е. то, что я допустил возможность того, что поищу за тебя и, если что, отпишусь, но не обещаю — это хамство?!

Хамство — это «А дальше читай про приведение типов». Типа ты уверен и проверил, что дальше всё доказывается элементарно, после прочтения про приведение типов. Хотя на самом деле ты просто не в курсе, как обосновывать дальше.

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

При чём тут какие-то константные указатели????

При том.

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

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

При том.

От вопроса про то, изменился ли массив, ты решил уйти?

По-моему, ты действительно троль

А по-моему — ты.

и дальнейший разговор бесполезен

С тобой так точно.

на любой разумный аргумент и цитату из стандарта ты будешь отвечать бредом

«При том» — это разумный аргумент и/или цитата из стандарта?

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

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

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

От вопроса про то, изменился ли массив, ты решил уйти?

Сейчас я тебе покажу на пальцах, на чём ты прокололся.

Сначала ты утверждал, что

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

А потом сказал:

Т.е, по-твоему, после a[0] = 0; массив не изменился???

Т. е. ты утверждаешь, что присвоил массиву новое значение, если понимать под массивом не ссылку на 0-й элемент, а весь контейнер. Но тогда первое твоё утверждение (в этом понимании) было ложью. Т. е. ты говоришь о совершенно разных вещах (в одном случае о ссылке, а в другом — о контейнере) и, пользуясь тем, что эти разные вещи называются одним словом, находишь какие-то несуществующие противоречия.

Я понимаю, что ты найдёшь множество демагогических «контр-аргументов». Но на таком уровне мне общаться просто неинтересно. Поэтому, если ты действительно чего-то не понимаешь, мой тебе совет — взять хорошую книжку по си (си++ в данном случае даже не нужен, там много дополнительных вещей, которые тебя только запутают, а соответствие массивов указателям верно и там, и там, и это азы, без которых ни си, ни си++ не понять). А на форуме без понимания этих азов тебе ничего объяснить не получится — формат не тот.

Ну а если ты всё это знаешь и просто тебе охота потролить от скуки, то ищи других тролей.

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

тратит свое время что бы понять

Я ему это только что объяснил. И дело не только во времени, но и в бесполезности таких объяснений без понимания азов тем, кому объясняют.

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

Сейчас я тебе покажу на пальцах, на чём ты прокололся.

Извини, но у тебя не вышло.

Сначала ты утверждал, что

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

Да. И ведь это действительно так! Например https://ideone.com/BdUzkI

Т. е. ты утверждаешь, что присвоил массиву новое значение

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

если понимать под массивом не ссылку на 0-й элемент, а весь контейнер.

Понимать можно как угодно. Так или иначе, я не говорил, что я присвоил массиву. И не присваивал массиву.

ты говоришь о совершенно разных вещах (в одном случае о ссылке, а в другом — о контейнере)

Откуда ты вообще взял что я говорю о ссылках или контейнерах? Это ты говоришь о каких-то константных указателях, но так и не объяснил толком, при чём тут они.

Я понимаю, что ты найдёшь множество демагогических «контр-аргументов».

Пока что тут ты демагогически приписываешь мне чушь, потом её героически опровергаешь и это, видимо, должно выглядеть так, что ты предъявил МНЕ контр-аргументы.

Из списка приёмов демагога:

Приписывание оппоненту слов, которые он не говорил.

Есть такое? Есть:

ты утверждаешь, что присвоил массиву

Я такого не утверждал.

Ещё приём демагога:

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

На вопрос «изменился ли массив» ясного ответа не последовало. На вопрос «при чём тут константные указатели» был получен ответ «при том». Потом пошли обвинения в троллинге.

Ну а если ты всё это знаешь

Да, я всё это знаю. В отличие от тебя.

охота потролить

Ещё раз повторяю, я не вбрасывал тут заведомо ложных утверждений с провокационными целями, т.е. я не троллю.

А то, что я пытаюсь получить внятные аргументы от оппонентов — это не троллинг.

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

В последний раз для танкистов:

Да, в последний раз, для тебя:

константным указателем на 0-й элемент

При чём тут константный указатель на нулевой элемент?

соответствие массивов указателям

У тебя есть внятные аргументы, подкреплённые пунктами стандарта, или «это азы» — всё, что у тебя есть?

совет — взять хорошую книжку по си

Это опять «ответ» на уровне

А дальше читай про приведение типов.

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

— это типичное хамство.

Серьезно? «Я может тебе помогу, незнакомый мне человек, но не точно, ибо времени нет у самогу» - это хамство? Или у тебя кроме с++ и с русским проблемы?

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

Т.е, по-твоему, после a[0] = 0; массив не изменился???

Ты путаешь определение массива из теории алгоритмики и из языка.

  char* ch = new char[100];
  std::array<char, 100> ch;

И то и другое является массивом по логике, но не по языку.

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

От вопроса про то, изменился ли массив, ты решил уйти?

Изменились данные. Массив остался на месте. В стандарте под массивом понимается не последовательный кусок байт из памяти.

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

Серьезно?

Да.

«Я может тебе помогу, незнакомый мне человек, но не точно, ибо времени нет у самогу» - это хамство?

Нет.

Или у тебя кроме с++ и с русским проблемы?

Не проецируй. Из моего сообщения понятно, что хамством я назвал не то, что мне не обещали помочь за неименеием времени, а посылание меня читать про что-то, при том, что посылающий не знает, поможет ли это.

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

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

Ты путаешь определение массива из теории алгоритмики и из языка.

С чего ты взял?

И то и другое является массивом по логике, но не по языку.

Под массивом я везде подразумеваю «массив по языку», т.е. то, что в стандарте называют «array object» или «object of array type».

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

Нет.

Но тебе дословно так и ответили, лол.

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

Изменились данные. Массив остался на месте.

Ну и что, что он остался на месте?

struct S { int a; } s {0};
s.a = 1

Изменился ли объект s?

int a = 0;
a = 1;

Изменился ли объект a?

Если объект a «остался на месте», то он не изменился после a = 1;, я правильно понял? Или такое определение изменения — остался или не остался на месте — относится только к массивам?

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

Ого. А это прогресс :)

Такими темпами, может быть, к 20-й странице появится правильный ответ на вопрос из ОП-поста =)

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

Такими темпами, может быть, к 20-й странице появится правильный ответ на вопрос из ОП-поста =)

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

Или ты не понимаешь вещей которые понятны вчем и не хочешь сам искать ответы? Тогда ты дурак.

Выбирай из двух зол=)

Dudraug ★★★★★
()

Вообще, во втором коде определённо присутствует UB.

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

Но на данный момент я скажу, что во втором коде определённо UB, а первый вроде ничего так.

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

Но на данный момент я скажу, что во втором коде определённо UB, а первый вроде ничего так.

Еще говоришь что не тролль? У тебя друзья то есть?

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

В общем, переписал первый код так, что в нём не должно остаться UB (я надеюсь).

Второму коду замена каста и launder не помогут, так что даже не стал его менять.

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

Не вижу причин, почему было бы не так.

http://eel.is/c++draft/expr.add#4

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i+j] if 0≤i+j≤n; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i−j] if 0≤i−j≤n; otherwise, the behavior is undefined.

А теперь что ты видишь?

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

Ничего нового? Учитывая (хотя приписка «by definition» не понятно к чему)

http://eel.is/c draft/expr.add#4

[...] The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [...]

Конечно паддинг может где-то быть, но для float не должно. А так если в одном случае будет UB, то и во втором тоже.

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

Ничего нового?

Что, совсем не смутило, что для арифметики указателей требуется указатель на элемент массива, а во втором случае (float*)stor — это не указатель на элемент массива?

А так если в одном случае будет UB, то и во втором тоже.

В первом случае точно нет UB из-за арифметики.

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

Что, совсем не смутило, что для арифметики указателей требуется указатель на элемент массива?

Если так интерпретировать, то контейнеры получаются с UB, разве нет? Они же выделяют память как байты, потом кастуют указатель и делают placement new поэлементно, а потом индексирование и арифметика с указателями применяются.

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

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

Если так интерпретировать, то контейнеры получаются с UB, разве нет?

Смотря как использовать, но вообще да, самому вектор-лайк контейнер на C++ без UB не написать. Единственное что можно сказать: раз стандарт говорит, что вектор работает, значит он работает, даже если его нельзя реализовать на C++.

В стандартной библиотеке вектор — не единственная вещь, которую нельзя написать на C++. Тот же offsetof сам на C++ без UB не сделаешь, но offsetof-ом из стандартной библиотеки пользоваться можно.

Они же выделяют память как байты, потом кастуют указатель и делают placement new поэлементно, а потом индексирование и арифметика с указателями применяются.

В operator[] у вектора можно нужно делать так, как в первом коде, тогда UB нет. А достать указатель из вектора (как адрес первого элемента или вызовом data()) и использовать его как указатель на первый элемент массива с точки зрения Core C++ — UB. Но если мы скажем, что раз стандарт разрешает так делать — то не UB.

Так как не написано, что массив должен быть правильного типа

expression P points to element x of an array object x with n elements

Должно именно указывать на существующий элемент (или на 1 гипотетический элемент за концом) существующего массива.

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

Меня это смущяет, так как это очень сильно ограничивает возможности расширения C++ классами. И вот это меня настораживает:

http://eel.is/c draft/expr.add#4

If the expression P points to element x of an array object x with n elements, <86>

Этого «if» не было бы, если бы абсолютно все указатели на объекты считались указателями на массивы. Сноска:

<86> An object that is not an array element is considered to belong to a single-element array for this purpose; see [expr.unary.op].

А там:

http://eel.is/c draft/expr.unary.op#3

For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), an object that is not an array element whose address is taken in this way is considered to belong to an array with one element of type T.

Может «address taken in another way» может существовать и на него не накладываются такие ограничения? Иначе мне тот «if» не понятен.

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

очень сильно ограничивает возможности расширения C++ классами

В смысле, не позволяет самостоятельно реализовывать вектор-лайк контейнеры? Есть такое, над исправлением подобного работают: http://wg21.link/p0593r2

Этого «if» не было бы, если бы абсолютно все указатели на объекты считались указателями на массивы.

Не совсем понимаю, что ты имеешь в виду.

Да, единичный объект с точки зрения адресной арифметики можно рассматривать как одноэлементный массив. Но во втором коде попытка использовать как трёхэлементный.

А if идёт в паре с «otherwise, the behavior is undefined».

Может «address taken in another way» может существовать и на него не накладываются такие ограничения?

Вряд ли такое есть в C++. Объект (в данном случае — массив из трёх float) либо есть, либо его нет, вне зависимости от того, как ты получил на него указатель. Неявно объекты в C++ не появляются. Пока что.

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

Тогда возражений нет, спасибо. Просто если это UB, то объёмы UB в существующем коде на C (там аналогичное скорее всего) и C++ в моём сознании только что возросло на несколько порядков.

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

Все (в т.ч. я) всегда интерпретировали

http://eel.is/c++draft/basic.life#1

The lifetime of an object of type T begins when
— storage with the proper alignment and size for type T is obtained, and
— if the object has non-vacuous initialization, its initialization is complete

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

Но некоторое время назад кому-то в комитете ударила моча в голову и решили, что это не верно, а объекты создаются только так:

An object is created by a definition, by a new-expression, when implicitly changing the active member of a union, or when a temporary object is created.

а те пункты про сторадж не являются дополнением этого правила.

(Честно говоря, с решением Партии я до сих пор до конца не согласен, ну да ладно.)

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

Да. Весь код с malloc нелегален.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0593r2.html#idiomatic-c-code-as-c

Consider the following natural C program:

struct X { int a, b; };
X *make_x() {
  X *p = (X*)malloc(sizeof(struct X));
  p->a = 1;
  p->b = 2;
  return p;
}
When compiled with a C++ compiler, this code has undefined behavior, because p->a attempts to write to an int subobject of an X object, and this program never created either an X object nor an int subobject.

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

В С++98:

An object is created by a definition (3.1), by a new-expression (5.3.4) or by the implementation (12.2) when needed.

Если нет зависимости от других определений, то судя по всему оно так всегда было.

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

Да, комитет решил, что типичный C-код, оказывается, всегда был сплошным UB с т.з. C++.

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

Неявно объекты в C++ не появляются.

Т.е. временные, конечно, появляются неявно.

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

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

Судя по всему, строго в терминах стандарта как-то так и надо (как бы ещё не пришлось использовать указатель, который вернул new, либо std::launder).

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

Мда, std::launder я упустил. Еще, конечно, не забыть ints[0].~int(), или как оно теперь будет.

Выглядит как-то абсурдно. Зачем всё это? Готовят что-то принципиально новое, типа лайфтаймов? Или уже сейчас есть проблемы с маллоками etc?

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

Еще, конечно, не забыть ints[0].~int(), или как оно теперь будет.

Не обязательно, можно просто освободить память.

Выглядит как-то абсурдно. Зачем всё это?

Чтобы усидеть на двух стульях: с одной стороны, разрешить относительно низкоуровневые вещи, типа выделения памяти malloc-ом или «создание» массива просто созданием подряд элементов в непрерывном куске памяти, а с другой не сваливаться полностью на уровень представления, а формально рассуждать о поведении C++-программ в терминах объектов, а не байтов.

Или уже сейчас есть проблемы с маллоками etc?

Нет, но надо формально объяснить, почему их нет.
Стандарт стандартизирует стандартные практики.

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