Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 30.08.2014, 21:48   #11
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Цитата:
Сообщение от 220Volt Посмотреть сообщение
как правильно создавать несколько указателей разного (сильно) типа на один объект.
Одного не понял - зачем это?
waleri вне форума Ответить с цитированием
Старый 30.08.2014, 21:53   #12
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Одного не понял - зачем это?
В хозяйстве пригодится ). Получил ругательство компилятора, неприятно когда чего-то не понимаешь, возникает желание разобраться.
220Volt вне форума Ответить с цитированием
Старый 01.09.2014, 00:14   #13
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Набросал небольшой тест, думаю он все достаточно просто объясняет. Идея следующая: в цикле пробегаем по массиву s и каждый проход суммируем в i.
Компилятор выбирает два способа построить код:
1. копить сумму в регистре, а сброс в память сделать при выходе из него.
2. на каждой итерации делать сброс в память.

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

Следует обратить внимание на взаиморасположение "!!! Сброс *i из регистра в память" и "!!! конец цикла".
g++ 1.cpp -O2 -S :
Код:
void f88888888(int *i, short *s, int count){    //---# 1
    int *s2 = (int*)s;
    for(; count > 0; --count)   *i += *s2++;
}
__Z9f88888888PiPsi:
        pushl	%ebx
        movl	16(%esp), %eax      // eax = count
        movl	8(%esp), %ebx       // ebx = i
        movl	12(%esp), %edx      // edx = s
        testl	%eax, %eax
        jle	L1                  // if(count == 0) goto L1
        movl	(%ebx), %ecx        // ecx = *i
        .p2align 4,,7
L4:
        addl	$4, %edx            // ++ s
        addl	-4(%edx), %ecx      // ecx += *(s - 1)
        subl	$1, %eax            // -- count
        movl	%ecx, (%ebx)        // *i = ecx               !!! Сброс *i из регистра в память
        jne	L4                  // if(count > 0) goto L4  !!! конец цикла
L1:
        popl	%ebx
        ret

void f88888888(int *i, short *s, int count){    //---# 2
    for(; count > 0; --count)   *i += *s++;
}
        jne	L5                      !!! конец цикла
        movl	%edx, (%esi)            !!! Сброс *i из регистра в память

void f88888888(int *i, int *s, int count){      //---# 3
    short *s2 = (short*)s;
    for(; count > 0; --count)   *i += *s2++;
}
        jne	L5                      !!! конец цикла
        movl	%edx, (%esi)            !!! Сброс *i из регистра в память

void f88888888(int *i, int count){              //---# 4
    int *s = (int *)0;
    for(; count > 0; --count)   *i += *s++;
}
        jne	L5                      !!! конец цикла
        movl	%edx, (%ebx)            !!! Сброс *i из регистра в память

void f88888888(int *i, int count){              //---# 5
    int *s = (int *)0x43422;
    for(; count > 0; --count)   *i += *s++;
}
        movl	%edx, (%ebx)            !!! Сброс *i из регистра в память
        jne	L4                      !!! конец цикла

void f88888888(int *i, int count){              //---# 6
    short g;
    int *s = (int *)&g;
    for(; count > 0; --count)   *i += *s++;
}
        jne	L5                      !!! конец цикла
        movl	%edx, (%ebx)            !!! Сброс *i из регистра в память

void f88888888(int *i, int count){              //---# 7
    char *s = (char *)0x3;
    for(; count > 0; --count)   *i += *s++;
}
	movl	%edx, (%ebx)            !!! Сброс *i из регистра в память
	jne	L4                      !!! конец цикла
       
void f88888888(char *i, int count){             //---# 8
    int *s = (int *)0x34;
    for(; count > 0; --count)
        *i += *s++;
}
	movb	%al, (%esi)             !!! Сброс *i из регистра в память
	jne	L4                      !!! конец цикла

Последний раз редактировалось 220Volt; 01.09.2014 в 00:30.
220Volt вне форума Ответить с цитированием
Старый 01.09.2014, 01:56   #14
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

По идее, так тоже можно:
Код:
uint32_t swaphalves(uint32_t a)
{
    char *p = (char*)&a, buf[2];
    buf[0] = p[0];
    buf[1] = p[1];
    p[0] = p[2];
    p[1] = p[3];
    p[2] = buf[0];
    p[3] = buf[1];
    return a;
}
220Volt вне форума Ответить с цитированием
Старый 01.09.2014, 03:25   #15
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

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

Лично я считаю, что если в коде есть reinterpret_cast, то с большой вероятностью, что-то где-то не так. Нужно как минимум попробовать от него избавиться. Ну а если оно еще и кастуется в неправильный тип - то ваще...

Ваши примеры с юнионом я не понял. Точнее, не понял почему компилятор не может из юниона выкидывать неиспользуемые поля. Я думаю может и никакой опасности это не несет.
rrrFer вне форума Ответить с цитированием
Старый 01.09.2014, 05:25   #16
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от 220Volt
Может кто-нибудь объяснить/показать пример пункта 4? У меня есть некоторые мысли, но не уверен.
Попробую ответить на свой вопрос (это мои размышления).
Код:
struct S{
    short fill;
    int val;
    void operator+=(const int &rhs) {this->val += rhs;}
};
void f88888888(S *i, int count){
    S *i2 = (S*)i;          // Валидное преобрзование, т.к. S содержит int
    int *s = (int *)0x323;
    for(; count > 0; --count)   *i2 += *s++;
}
__Z9f88888888P1Si:
	pushl	%ebx
	movl	12(%esp), %ecx      // ecx = count
	movl	8(%esp), %ebx       // ebx = i
	testl	%ecx, %ecx
	jle	L1
	movl	4(%ebx), %edx       // edx = S.val
	xorl	%eax, %eax
	.p2align 4,,7
L4:
	addl	803(,%eax,4), %edx  // edx += *s
	addl	$1, %eax            // ++ count
	cmpl	%ecx, %eax
	movl	%edx, 4(%ebx)       // !!! Сброс *i из регистра в память
	jne	L4                  // !!! конец цикла
L1:
	popl	%ebx
	ret
//----------------------------------------------------------------------

struct S{
    short fill;
    short val;
    void operator+=(const int &rhs) {this->val += rhs;}
};
void f88888888(int *i, int count){
    S *i2 = (S*)i;                // Невалидное преобрзование
    int *s = (int *)0x323;
    for(; count > 0; --count)   *i2 += *s++;
}
__Z9f88888888Pii:
	pushl	%ebx
	movl	12(%esp), %ecx      // ecx = count
	movl	8(%esp), %ebx       // ebx = i
	testl	%ecx, %ecx
	jle	L1
	movzwl	2(%ebx), %edx       // edx = S.val
	xorl	%eax, %eax
	.p2align 4,,7
L5:
	addw	803(,%eax,4), %dx   // edx += *s
	addl	$1, %eax            // ++ count
	cmpl	%ecx, %eax
	jne	L5                  // !!! конец цикла
	movw	%dx, 2(%ebx)        // !!! Сброс *i из регистра в память, слишком поздно.
L1:
	popl	%ebx
	ret
Во втором варианте сумма держится в регистре, но указатели могут пересекаться, в итоге будет ошибка. Первый вариант отрабатывает правильно.

Последний раз редактировалось 220Volt; 01.09.2014 в 05:28.
220Volt вне форума Ответить с цитированием
Старый 01.09.2014, 08:33   #17
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Цитата:
Сообщение от 220Volt Посмотреть сообщение
Получил ругательство компилятора, неприятно когда чего-то не понимаешь, возникает желание разобраться.
Это понятно, вопрос был что пытались сделать, что получили предупреждение от компилятора.
waleri вне форума Ответить с цитированием
Старый 01.09.2014, 08:39   #18
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Использовал placement new, ну а полученный буфер кастовл.
220Volt вне форума Ответить с цитированием
Старый 05.09.2014, 11:15   #19
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Код:
#include <stdio.h>
#include <new>
struct Base{
    virtual void f() {printf("base\n");}
};
struct Child : Base{
    void f()override {printf("child\n");}
};
alignas(Child) char buf[sizeof(Child)];
union Ptr{
    Base base;
};
union Ptr2{
    Child child;
};
int main(){
    new(buf) Child;
    Ptr *ptr = reinterpret_cast<Ptr*>(buf);      // invalid
    //-------------------printf: base---//
    ptr->base.f();                      //
    Base &b = ptr->base;                //
    b.f();                              //
    //----------------------------------//
    //-------------------printf: child--//
    Base *b2 = &ptr->base;              //
    b2->f();                            //
    //----------------------------------//
    Ptr2 *ptr2 = reinterpret_cast<Ptr2*>(buf);   // ok
    Base *ptr3 = reinterpret_cast<Base*>(buf);   // ok
    Child *ptr4 = reinterpret_cast<Child*>(buf);   // ok
}
220Volt вне форума Ответить с цитированием
Старый 06.04.2015, 13:48   #20
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Например, код:
Код:
#include <iostream>
#include <type_traits>

using namespace std;

static std::aligned_storage<100>::type storage;

struct A{
    int i;
};

struct B{
    int i;
};

int main() {
    A *a = reinterpret_cast<A*>(&storage);
    a->i = 0;
    // алгоритм №1, выполняем действия с a

    B *b = reinterpret_cast<B*>(&storage);
    b->i = 0;
    // алгоритм №2, выполняем действия с b

    std::cout << b->i;
    return 0;
}
В принципе, reinterpret_cast можно заменить на placement new, но его код мне неизвестен, а хотелось бы разобраться.

Правила мы нарушаем, это ясно, интересует - как это сделать грамотно?
Чего я опасаюсь? Такого сценария:
1. Выполняем первый алгоритм
2. В регистрах, после первого алгоритма, что-то остаётся (сброс в память не выполнен).
3. Выполняем второй алгоритм.

Нужна гарантия того, что после первого алгоритма все операции по записи из регистров завершены. Когда такие гарантии, с точки зрения стандарта, имеются?
220Volt вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
С++ not implemented in type 'istream' for arguments of type 'float *'из-за чего эта ошибка и как исправить? Mitax-47 Помощь студентам 1 10.05.2013 15:48
Could not convert variant of the type (String) into type (Boolean) Silly Student C++ Builder 0 19.11.2011 13:06
Отличие type T = Object от type T = Class? Warn Общие вопросы Delphi 8 04.11.2011 19:20
Could not convert variant of type (Olestr) into type (Double) java_91 Общие вопросы Delphi 1 18.02.2011 18:46
Could not convert variant of type (UnicodeString) into type (Double) postaveche БД в Delphi 11 13.12.2010 16:41