Дурацкий вопрос
От: kov_serg Россия  
Дата: 23.11.24 12:54
Оценка: -1 :)
Почему 2 и 3 строчки не константы ?
const int c1=(char*)1-(char*)0;
enum { c2=(char*)1-(char*)0 };
constexpr int c3=(char*)1-(char*)0;
Re: Дурацкий вопрос
От: Pavel Dvorkin Россия  
Дата: 23.11.24 13:24
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

_>constexpr int c3=(char*)1-(char*)0;


Насколько я понимаю, тут фактически reinterpret_cast.


The following solution:

class C {
public:
static constexpr const void* noop = reinterpret_cast<const void*>(0x1);
};
Although, it compiles and works fine in GCC isn't valid C++ (e.g., it doesn't compile with either clang or VC++2013) because according to the standard § 5.19/2 Constant Expressions [expr.const] the result of a reinterpret_cast can't be a constant expression.


https://stackoverflow.com/questions/24397797/statically-casting-an-integer-to-pointer-type
With best regards
Pavel Dvorkin
Отредактировано 23.11.2024 13:25 Pavel Dvorkin . Предыдущая версия .
Re: Дурацкий вопрос
От: vopl Россия  
Дата: 23.11.24 13:49
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

_>Почему 2 и 3 строчки не константы ?

_>
_>const int c1=(char*)1-(char*)0;
_>enum { c2=(char*)1-(char*)0 };
_>constexpr int c3=(char*)1-(char*)0;
_>


Для того чтобы быть использованым во 2 и 3 строчках, выражение должно быть core-constant-expression, а в таковых запрещен reinterpret_cast, который у тебя задействуется для integer-to-pointer преобразований.
Re[2]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 24.11.24 10:55
Оценка: :)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, kov_serg, Вы писали:


_>>constexpr int c3=(char*)1-(char*)0;


PD>Насколько я понимаю, тут фактически reinterpret_cast.



PD>

PD>The following solution:

PD>class C {
PD>public:
PD> static constexpr const void* noop = reinterpret_cast<const void*>(0x1);
PD>};
PD>Although, it compiles and works fine in GCC isn't valid C++ (e.g., it doesn't compile with either clang or VC++2013) because according to the standard § 5.19/2 Constant Expressions [expr.const] the result of a reinterpret_cast can't be a constant expression.


PD>https://stackoverflow.com/questions/24397797/statically-casting-an-integer-to-pointer-type


Это понятно, что сделано максимально через жопу, но в чем сакральный смысл так делать? Почему 1 не константа?
Re[3]: Дурацкий вопрос
От: Pavel Dvorkin Россия  
Дата: 24.11.24 12:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Это понятно, что сделано максимально через жопу, но в чем сакральный смысл так делать? Почему 1 не константа?


1 — константа, а вот преобразование типа не может быть выполнено в compile-time. В общем случае такое преобразование для указателей даже не гарантирует , что численное значение не изменится.
With best regards
Pavel Dvorkin
Re: Дурацкий вопрос
От: B0FEE664  
Дата: 25.11.24 11:13
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Почему 2 и 3 строчки не константы ?

_>
_>const int c1=(char*)1-(char*)0;
_>enum { c2=(char*)1-(char*)0 };
_>constexpr int c3=(char*)1-(char*)0;
_>


Я не знаю насчёт констант, но если я правильно помню, то все три выражения — это неопределённое поведение, так как разницу между указателями можно брать, только если указуемое принадлежат одному объекту или один (или оба указателя) указывает на следующий за объектом адрес.
Я затрудняюсь с ответом на вопрос: есть ли гарантия, что следующие указатели будут равны?:
char* p1 = (char*)0;
char* p2 = 0;
assert(p1 == p2);

но склоняюсь к ответу, что гарантии равенства по стандарту нет (implementation defined ЕМНИП).

Так что — да, для меня это какой-то дурацкий вопрос.
И каждый день — без права на ошибку...
Re[2]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 25.11.24 11:34
Оценка: +1 -1 :)
Здравствуйте, B0FEE664, Вы писали:

BFE>но склоняюсь к ответу, что гарантии равенства по стандарту нет (implementation defined ЕМНИП).

Арифметика с char* разрешена. Так в чем проблема?
(char*)(a+b)-(char*)a = b или не очень?

BFE>Так что — да, для меня это какой-то дурацкий вопрос.

Все ответы на которые не удобно отвечать в C++ принято помечать как UB и от&$итесь

1. стандарт всегда прав
2. если стандарт не прав смотри путкт 1

Re[3]: Дурацкий вопрос
От: B0FEE664  
Дата: 25.11.24 16:48
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>но склоняюсь к ответу, что гарантии равенства по стандарту нет (implementation defined ЕМНИП).

_>Арифметика с char* разрешена.
Только в пределах одного объекта.

_>Так в чем проблема?

ЕМНИП:
Нигде не сказано, что память плоская.
Нигде не сказано, что память линейная.

_>(char*)(a+b)-(char*)a = b или не очень?

Если указатель из себя представляет сегмент и смещение в нём, то как тогда?

BFE>>Так что — да, для меня это какой-то дурацкий вопрос.

_>Все ответы на которые не удобно отвечать в C++ принято помечать как UB и от&$итесь
_>

_>1. стандарт всегда прав
_>2. если стандарт не прав смотри путкт 1

Либо свобода и никакой конкретности, либо определённость и никакой свободы. Вы за свободу или как?
И каждый день — без права на ошибку...
Re[4]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 25.11.24 22:43
Оценка: :)
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, kov_serg, Вы писали:


BFE>>>но склоняюсь к ответу, что гарантии равенства по стандарту нет (implementation defined ЕМНИП).

_>>Арифметика с char* разрешена.
BFE>Только в пределах одного объекта.
А с чего вы взяли что это не впределах одного объекта.

_>>Так в чем проблема?

BFE>ЕМНИП:
BFE>Нигде не сказано, что память плоская.
BFE>Нигде не сказано, что память линейная.
Точно кругом черные дыры искривляющие пространство память.
Так и как же работает https://en.cppreference.com/w/cpp/memory/addressof ?

_>>(char*)(a+b)-(char*)a = b или не очень?

BFE>Если указатель из себя представляет сегмент и смещение в нём, то как тогда?
Оно даже с сегментами работает если впределах одного сегмента.

BFE>Либо свобода и никакой конкретности, либо определённость и никакой свободы. Вы за свободу или как?

Никаких крайностей только разумный баланс.
Re[5]: Дурацкий вопрос
От: Кодт Россия  
Дата: 25.11.24 23:53
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Так и как же работает https://en.cppreference.com/w/cpp/memory/addressof ?


Он вообще к адресной арифметике отношения не имеет.
addressof — это хак против перегрузки оператора &.
Перекуём баги на фичи!
Re: Дурацкий вопрос
От: Кодт Россия  
Дата: 26.11.24 00:13
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Почему 2 и 3 строчки не константы ?

_>
_>const int c1=(char*)1-(char*)0;
_>enum { c2=(char*)1-(char*)0 };
_>constexpr int c3=(char*)1-(char*)0;
_>


Потому что это всё — не константы времени компиляции?

Адресная арифметика определена только в пределах одного массива.
За его пределами — поведение как минимум, не специфицировано. (А точнее, это UB, на которое все закрывают глаза).

Даже вот так — нельзя
char x;
char y;

constexpr int d = &y - &x;

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

А вот так — можно
char x[] = "12345";

constexpr int d = &x[3] - &x[1];

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

А вот так — gcc считает, что можно, а clang — что нельзя
struct foo {
  char x;
  int y;
  char z;
};

foo f;

constexpr int d = &f.z - &f.x;

И я, пожалуй, соглашусь с clang: потому что в общем случае можно нахимичить с выравниванием, и для типов, чей sizeof не равен 1, адресная арифметика окажется дробной.

Надо покурить стандарт, где должно быть сказано, что при наличии таких хаков (а тем более, реинтерпретов (char*)1) программа становится ill-formed, no diagnostic required.

Встречный вопрос:
А ЗАЧЕМ?
Перекуём баги на фичи!
Re[2]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 26.11.24 04:18
Оценка:
Здравствуйте, Кодт, Вы писали:


К>Встречный вопрос:

К>А ЗАЧЕМ?

Хотелось шаблон параметризировать смещенем поля структуры
Re[6]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 26.11.24 04:27
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, kov_serg, Вы писали:


_>>Так и как же работает https://en.cppreference.com/w/cpp/memory/addressof ?


К>Он вообще к адресной арифметике отношения не имеет.

К>addressof — это хак против перегрузки оператора &.

В C++ так принято не длелать еднообразно, а выполнять решения простых задач с помощью хаков.
Re[3]: Дурацкий вопрос
От: vopl Россия  
Дата: 26.11.24 04:56
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, Кодт, Вы писали:



К>>Встречный вопрос:

К>>А ЗАЧЕМ?

_>Хотелось шаблон параметризировать смещенем поля структуры


https://en.cppreference.com/w/cpp/types/offsetof
Re[4]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 26.11.24 05:46
Оценка:
Здравствуйте, vopl, Вы писали:

_>>Хотелось шаблон параметризировать смещенем поля структуры


V>https://en.cppreference.com/w/cpp/types/offsetof


Не. Надо &Type::field -> offset
get_offset<&Type::field>();
Отредактировано 26.11.2024 5:47 kov_serg . Предыдущая версия .
Re[5]: Дурацкий вопрос
От: so5team https://stiffstream.com
Дата: 26.11.24 07:51
Оценка: 11 (1) +1
Здравствуйте, kov_serg, Вы писали:

_>>>Хотелось шаблон параметризировать смещенем поля структуры


V>>https://en.cppreference.com/w/cpp/types/offsetof


_>Не. Надо &Type::field -> offset

_>
_>get_offset<&Type::field>();
_>


Так ведь указатель на член -- это же не смещение. Т.е. смещение для одного и того же члена может быть разным в зависимости от объекта, к которому затем этот указатель применяется:
#include <iostream>

struct A {
    int m_a{};
};

struct B : public A {
    int m_b{};
};

struct C {
    int m_c{};
};

struct D : C, A {
    int m_d{};
};

int main()
{
    using FieldPtr = int A::*;

    B b;
    b.m_a = 1;
    D d;
    d.m_a = 2;

    FieldPtr p1 = &A::m_a;

    std::cout << "B: " << b.*p1 << ", offsetof: " << offsetof(B, m_a) << std::endl;
    std::cout << "D: " << d.*p1 << ", offsetof: " << offsetof(D, m_a) << std::endl;
}
Отредактировано 26.11.2024 8:00 so5team . Предыдущая версия .
Re[5]: Дурацкий вопрос
От: σ  
Дата: 26.11.24 08:56
Оценка:
_>Так и как же работает https://en.cppreference.com/w/cpp/memory/addressof ?
https://github.com/llvm/llvm-project/blob/bb8bf858e865ec3119352bdef43c09adb4c93b31/libcxx/include/__memory/addressof.h#L21-L24
Re[6]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 26.11.24 09:12
Оценка:
Здравствуйте, so5team, Вы писали:

S>Так ведь указатель на член -- это же не смещение. Т.е. смещение для одного и того же члена может быть разным в зависимости от объекта, к которому затем этот указатель применяется:


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

Типа такого:
template<class M,class T> int get_ofs(M T::* p) { return (int)(char*)&(((T*)0)->*p); }


Что бы не писать вручную
#include <iostream>
template<class T>struct get_base_type;
template<class M,class T> struct get_base_type<M T::*> { typedef T base; typedef M value; };
template<class T,T t>struct get_id;
#define DECL_ID(mp,v) template<> struct get_id<decltype(&mp),&mp> { \
    enum { id=v }; \
    typedef decltype(&mp) type; \
    typedef get_base_type<type>::base base; \
    typedef get_base_type<type>::value value; \
};
#define GET_ID(mp) (get_id<decltype(&mp),&mp>::id)

struct A {
    int x,y; double z;
};

DECL_ID(A::x,1)
DECL_ID(A::y,2)
DECL_ID(A::z,3)

int main(int argc, char const *argv[]) {
    std::cout
        <<"A::x="<<GET_ID(A::x)<<"\n"
        <<"A::y="<<GET_ID(A::y)<<"\n"
        <<"A::z="<<GET_ID(A::z)<<"\n"
    ;return 0;
}
Отредактировано 26.11.2024 9:50 kov_serg . Предыдущая версия . Еще …
Отредактировано 26.11.2024 9:48 kov_serg . Предыдущая версия .
Отредактировано 26.11.2024 9:40 kov_serg . Предыдущая версия .
Отредактировано 26.11.2024 9:38 kov_serg . Предыдущая версия .
Отредактировано 26.11.2024 9:35 kov_serg . Предыдущая версия .
Отредактировано 26.11.2024 9:24 kov_serg . Предыдущая версия .
Отредактировано 26.11.2024 9:24 kov_serg . Предыдущая версия .
Отредактировано 26.11.2024 9:13 kov_serg . Предыдущая версия .
Re[6]: Дурацкий вопрос
От: kov_serg Россия  
Дата: 26.11.24 09:14
Оценка:
Здравствуйте, σ, Вы писали:

_>>Так и как же работает https://en.cppreference.com/w/cpp/memory/addressof ?

σ>https://github.com/llvm/llvm-project/blob/bb8bf858e865ec3119352bdef43c09adb4c93b31/libcxx/include/__memory/addressof.h#L21-L24

__builtin_addressof
Re[5]: Дурацкий вопрос
От: B0FEE664  
Дата: 26.11.24 13:44
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>>>но склоняюсь к ответу, что гарантии равенства по стандарту нет (implementation defined ЕМНИП).

_>>>Арифметика с char* разрешена.
BFE>>Только в пределах одного объекта.
_>А с чего вы взяли что это не впределах одного объекта.
Объект расположенный по адресу 0?

_>Точно кругом черные дыры искривляющие пространство память.

И вообще, бывает что адрес — IPv4

_>Так и как же работает https://en.cppreference.com/w/cpp/memory/addressof ?

Действительно, как же он работает? Погодите..., а может он берёт адрес объекта? Да — не, быть не может!

_>>>(char*)(a+b)-(char*)a = b или не очень?

BFE>>Если указатель из себя представляет сегмент и смещение в нём, то как тогда?
_>Оно даже с сегментами работает если впределах одного сегмента.
если.
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.