Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 5.00
CEBEP
107 / 107 / 9
Регистрация: 21.03.2010
Сообщений: 444
#1

Сложение указателей - C++

01.05.2012, 18:01. Просмотров 1589. Ответов 16
Метки нет (Все метки)

Чисто декларативно замечу что это не безсмысленная операция, как нам о том повествуют всюду.
пример:
C++
1
2
3
    ExpressionEdit* a = split ? leftInsert : rightInsert;
    ExpressionEdit* b = split ? rightInsert : leftInsert;
    split = !split;
можно бы было реализовать без второй операции ветвления следующим образом:
C++
1
2
3
    ExpressionEdit* a = split ? leftInsert : rightInsert;
    ExpressionEdit* b = rightInsert + leftInsert - a;
    split = !split;
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.05.2012, 18:01
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Сложение указателей (C++):

Сложение двух указателей - C++
Как сложить 2 указателя? Если нельзя, то почему?

по поводу указателей. Как правильно задавать массив указателей и его удалять? - C++
Т.е., например создаю указатель: TPoint *p_Point=NULL; а если массив? TPoint *p_MassPoint; //=?; как массив обнулить не ясно ...

Почему в сортировке указателей на объекты в вызове функции используются адреса объектов, а не указателей? - C++
Доброго времени суток! Рассматриваю пример (из Лафоре) сортировки массива указателей на объекты, для чего используются указатели на...

Создать специфицированный шаблон функции, принимающей массив указателей на char и количество самих указателей - C++
Задача: создать специфицированный шаблон функции, принимающей массив указателей на char и количество самих указателей. Вернуть адрес...

Объяснить различия в работе указателей на целое число и указателей на const char (строки в стиле Си) - C++
Уважаемые программисты, возникло несколько вопросов касательно указателей. Почему при выводе указателя на int нужна звёздочка (*), а...

Создать специализацию для шаблона, которая принимает массив указателей на строки и количество этих указателей - C++
Нужно создать специализацию для шаблона, которая принимает массив указателей на строки и количество этих указателей. Эта специализация...

16
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
01.05.2012, 18:05 #2
CEBEP, стандарт с вами не согласится

A subtraction of two pointers is only granted to have a valid defined value for pointers to elements of the same array (or for the element just past the last in the array).

For other values, the behavior depends on the system characteristics and compiler implementation.
кроме того второй код вразы психоделичней
0
CEBEP
107 / 107 / 9
Регистрация: 21.03.2010
Сообщений: 444
01.05.2012, 18:21  [ТС] #3
Цитата Сообщение от alex_x_x Посмотреть сообщение
CEBEP, стандарт с вами не согласится
В чём конкретно он со мной не согласится? То что эти указатели не объедены массивом это весомый момент, но, думаю, степень гипотетичности всего выражения в целом позволяет закрыть на это глаза, ведь сложение указателей должно будет вернуть указатель который вовсе не обязан иметь смысл как таковой, а лишь должен быть использован как левый аргумент в операции вычитания.
Да и вообще что толку апеллировать к стандарту, если зашла речь о сущности которую он предал анафеме? Я просто хотел заметить что чисто алгебраически такая операция может иметь смысл.
0
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
01.05.2012, 18:24 #4
Цитата Сообщение от CEBEP Посмотреть сообщение
В чём конкретно он со мной не согласится? То что эти указатели указывают не объеденные массивом это весомый момент, но, думаю, степень гипотетичности всего выражения в целом позволяет закрыть на это глаза, ведь сложение указателей должно будет вернуть указатель который вовсе не обязан иметь смысл как таковой, а лишь должен быть использован как левый аргумент в операции вычитания.
разность указателей дает тип ptrdiff_t
то что нельзя просто так орудовать с указателями говорит стандарт и эта тема [Задача] Адресная арифметика
1
DU
1484 / 1130 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
01.05.2012, 18:28 #5
может быть и можно было бы второй вариант использовать, но для чего?
для обфускации, чтобы враги дольше код понимали?
0
CEBEP
107 / 107 / 9
Регистрация: 21.03.2010
Сообщений: 444
01.05.2012, 18:45  [ТС] #6
Цитата Сообщение от DU Посмотреть сообщение
для чего?
по моему второй вариант должен выполнятся существенно быстрее
0
DU
1484 / 1130 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
01.05.2012, 18:50 #7
копеечная оптимизация, да и то не факт. нужно в асм смотреть после компиляции с оптимизацией или замеры делать. в любом случае на производительность программы в целом это врятли повлияет. зато код стал такой хитромудрый, что не каждый его сможет осознать.
0
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
01.05.2012, 18:54 #8
Цитата Сообщение от CEBEP Посмотреть сообщение
rightInsert + leftInsert - a;
по угару
если rightInsert и leftInsert у верхней границы адресов, то rightInsert + leftInsert может дать переполнение (на 32битах) и результатом будет невалидный указатель
0
CEBEP
107 / 107 / 9
Регистрация: 21.03.2010
Сообщений: 444
01.05.2012, 18:55  [ТС] #9
Цитата Сообщение от DU Посмотреть сообщение
копеечная оптимизация
Не понимаю попытки доказать что это бессмысленно. Строго говоря, я обратного и не утверждал
Цитата Сообщение от alex_x_x Посмотреть сообщение
результатом будет невалидный указатель
да, я об этом прямо упоминал во втором своём сообщении...
0
grizlik78
Эксперт С++
1967 / 1460 / 120
Регистрация: 29.05.2011
Сообщений: 3,020
01.05.2012, 19:09 #10
C++
1
2
3
4
5
6
7
ExpressionEdit* a = rightInsert;
ExpressionEdit* b = leftInsert;
if (split) {
    a = leftInsert;
    b = rightInsert;
}
split = !split;
Оставьте уже машинную оптимизацию компилятору. Это его работа.

Добавлено через 1 минуту
Или даже так (хотя мне предыдущий больше по душе)
C++
1
2
3
4
5
6
7
8
9
10
ExpressionEdit* a;
ExpressionEdit* b;
if (split) {
    a = leftInsert;
    b = rightInsert;
} else {
    a = rightInsert;
    b = leftInsert;
}
split = !split;
0
DU
1484 / 1130 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
01.05.2012, 19:15 #11
вы ассемблерный код то хотябы видели?
у вас там две арифметические операции с указателями. значит будет один промежуточный результат, его нужно в регистрах хранить что-то делать с этим всем. + не забыть учесть, что в арифметике указателей еще неявно учавствует размер. т.е. возможно там еще и умножение в каждой операции будет
Вот какой ассемблер у меня получился в дебаге:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
  int* p1 = b ? left : right;
0041332E  movzx       eax,byte ptr [b] 
00413332  test        eax,eax 
00413334  je          F1+31h (413341h) 
00413336  mov         ecx,dword ptr [left] 
00413339  mov         dword ptr [ebp-0DCh],ecx 
0041333F  jmp         F1+3Ah (41334Ah) 
00413341  mov         edx,dword ptr [right] 
00413344  mov         dword ptr [ebp-0DCh],edx 
0041334A  mov         eax,dword ptr [ebp-0DCh] 
00413350  mov         dword ptr [p1],eax 
  int* p2 = b ? right : left;
00413353  movzx       eax,byte ptr [b] 
00413357  test        eax,eax 
00413359  je          F1+56h (413366h) 
0041335B  mov         ecx,dword ptr [right] 
0041335E  mov         dword ptr [ebp-0DCh],ecx 
00413364  jmp         F1+5Fh (41336Fh) 
00413366  mov         edx,dword ptr [left] 
00413369  mov         dword ptr [ebp-0DCh],edx 
0041336F  mov         eax,dword ptr [ebp-0DCh] 
00413375  mov         dword ptr [p2],eax 
*/
void F1(bool b, int* left, int* right)
{
  int* p1 = b ? left : right;
  int* p2 = b ? right : left;
}
 
/*
  int* p1 = b ? left : right;
00412E5C  movzx       eax,byte ptr [b] 
00412E60  test        eax,eax 
00412E62  je          F2+3Fh (412E6Fh) 
00412E64  mov         ecx,dword ptr [left] 
00412E67  mov         dword ptr [ebp-0F4h],ecx 
00412E6D  jmp         F2+48h (412E78h) 
00412E6F  mov         edx,dword ptr [right] 
00412E72  mov         dword ptr [ebp-0F4h],edx 
00412E78  mov         eax,dword ptr [ebp-0F4h] 
00412E7E  mov         dword ptr [p1],eax 
  int* p2 = left + x - y;
00412E81  mov         eax,dword ptr [x] 
00412E84  mov         ecx,dword ptr [left] 
00412E87  lea         edx,[ecx+eax*4] 
00412E8A  mov         eax,dword ptr [y] 
00412E8D  shl         eax,2 
00412E90  sub         edx,eax 
00412E92  mov         dword ptr [p2],edx 
*/
void F2(bool b, int* left, int* right)
{
  int x = 10;
  int y = 20;
  int* p1 = b ? left : right;
  int* p2 = left + x - y;
}
 
 
/*
  int* p1 = right;
0041277E  mov         eax,dword ptr [right] 
00412781  mov         dword ptr [p1],eax 
  int* p2 = left;
00412784  mov         eax,dword ptr [left] 
00412787  mov         dword ptr [p2],eax 
  if (b)
0041278A  movzx       eax,byte ptr [b] 
0041278E  test        eax,eax 
00412790  je          F3+3Eh (41279Eh) 
  {
    p1 = right;
00412792  mov         eax,dword ptr [right] 
00412795  mov         dword ptr [p1],eax 
    p2 = left;
00412798  mov         eax,dword ptr [left] 
0041279B  mov         dword ptr [p2],eax 
  }
*/
void F3(bool b, int* left, int* right)
{
  int* p1 = right;
  int* p2 = left;
  if (b)
  {
    p1 = right;
    p2 = left;
  }
}

Если вы специалист - считайте такты. Кстати, ваш код даже не компилируется в студии.
2
grizlik78
Эксперт С++
1967 / 1460 / 120
Регистрация: 29.05.2011
Сообщений: 3,020
01.05.2012, 19:26 #12
Цитата Сообщение от DU Посмотреть сообщение
Кстати, ваш код даже не компилируется в студии.
Ну он и не говорил, что компилируется. Это были размышления на тему "Ах если бы, ах если бы... Не жизнь была, а песня бы..."

Добавлено через 6 минут
Кстати, даже если допустить правильность и полезность подобной конструкции, то сложение указателей всё-равно не нужно.
C++
1
ExpressionEdit* b = rightInsert + (leftInsert - a);
1
Toshkarik
1143 / 860 / 51
Регистрация: 03.08.2011
Сообщений: 2,390
Завершенные тесты: 1
01.05.2012, 19:26 #13
Ну можно тогда вообще так
C++
1
flag ? ( a = b, c = d ) : ( a = d, c = b );
0
CEBEP
107 / 107 / 9
Регистрация: 21.03.2010
Сообщений: 444
01.05.2012, 19:35  [ТС] #14
Цитата Сообщение от DU Посмотреть сообщение
Кстати, ваш код даже не компилируется в студии.
Второй вариант кода я и не пытался компилировать потому что был уверен что он не должен был компилироваться. То что у вас есть компилятор который это проглотил меня удивило.

Цитата Сообщение от grizlik78 Посмотреть сообщение
сложение указателей всё-равно не нужно.
ну в том варианте в котором вы предложили есть ссылка на
Цитата Сообщение от alex_x_x Посмотреть сообщение
A subtraction of two pointers is only granted to have a valid defined value for pointers to elements of the same array (or for the element just past the last in the array). For other values, the behavior depends on the system characteristics and compiler implementation.
0
grizlik78
Эксперт С++
1967 / 1460 / 120
Регистрация: 29.05.2011
Сообщений: 3,020
01.05.2012, 20:04 #15
Цитата Сообщение от CEBEP Посмотреть сообщение
То что у вас есть компилятор который это проглотил меня удивило
Нет у него такого компилятора. Там просто целые складываются.


Цитата Сообщение от CEBEP Посмотреть сообщение
ну в том варианте в котором вы предложили есть ссылка на
A subtraction of two pointers is only granted to have a valid defined value for pointers to elements of the same array (or for the element just past the last in the array). For other values, the behavior depends on the system characteristics and compiler implementation.
Разумеется. Но это-то, кстати, можно предусмотреть, выделяя элементы из одного массива
Но Баба-Яга всё-равно против

Добавлено через 25 минут
Ну и чтобы показать, насколько программист может усложнить "жизнь" компилятору, посмотрим, что делает GCC4.5 в режиме оптимизации -O3
Скомпилированы следующие 3 функции:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bool F1(bool b, int* left, int* right)
{
  int* p1 = b ? left : right;
  int* p2 = b ? right : left;
  return p1 > p2;
}
 
bool F2(bool b, int* left, int* right)
{
  int* p1 = b ? left : right;
  int* p2 = left + (right - p1);
  return p1 > p2;
}
 
bool F3(bool b, int* left, int* right)
{
  int* p1 = right;
  int* p2 = left;
  if (b)
  {
    p1 = left;
    p2 = right;
  }
  return p1 > p2;
}
Первая породила такой код:
Assembler
1
2
3
4
5
6
7
8
9
    .cfi_startproc
    testb   %dil, %dil
    movq    %rsi, %rax
    cmove   %rdx, %rax
    cmovne  %rdx, %rsi
    cmpq    %rsi, %rax
    seta    %al
    ret
    .cfi_endproc
Ну, в общем, что просили, то и получили.

Из второй вышло такое:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    .cfi_startproc
    xorl    %eax, %eax
    testb   %dil, %dil
    je  .L5
    movq    %rdx, %rax
    movq    %rsi, %rdx
    subq    %rsi, %rax
    andq    $-4, %rax
.L5:
    addq    %rax, %rsi
    cmpq    %rsi, %rdx
    seta    %al
    ret
    .cfi_endproc
Разве стало эффективнее? В прошлый раз были условные пересылки, но не было ветвления. Здесь же увы, условный переход.

Третий код оказался идентичным первому.
Assembler
1
2
3
4
5
6
7
8
9
    .cfi_startproc
    testb   %dil, %dil
    movq    %rsi, %rax
    cmovne  %rdx, %rax
    cmove   %rdx, %rsi
    cmpq    %rax, %rsi
    seta    %al
    ret
    .cfi_endproc
Вариант Toshkarik даёт тоже точно такой код.
Выбирайте

DU, у тебя в третьей функции ошибка. По условию выполняется то же, что и без условия.
1
01.05.2012, 20:04
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.05.2012, 20:04
Привет! Вот еще темы с ответами:

Различия указателей char* от указателей других типов - C++
Помогите пожалуйста разобраться! Прочитал раздел про указатели и даже вроде бы понял. Что касается указателей на тип int. Но что...

Как обойтись без указателей и указателей на указатель? - C++
Ибо не совсем выходит понять,что на что тут указывает #include "stdafx.h" #include <iostream> #include <stdlib.h> using namespace...

Создание массивов указателей на массивы указателей - C++
Помогите в решении задачи: создал массив указателей на массивы указателей на строки, но компилятор ругается на то что не может...

Добавление нового указателя в конец массива указателей, удаление указанного элемента, добавление указателей - C++
Здравствуйте. Помогите, пожалуйста, разобраться с одним большим заданием. Задание пока в процессе написания, но уже наверное есть ошибки....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru