Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.95/21: Рейтинг темы: голосов - 21, средняя оценка - 4.95
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
1

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

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

Author24 — интернет-сервис помощи студентам
Чисто декларативно замечу что это не безсмысленная операция, как нам о том повествуют всюду.
пример:
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
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.05.2012, 18:01
Ответы с готовыми решениями:

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

сложение 2 указателей в функции
здравствуйте есть такая задача ф-цию add, которая принимает два указателя на int, складывает...

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

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

16
бжни
2473 / 1684 / 135
Регистрация: 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
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
01.05.2012, 18:21  [ТС] 3
Цитата Сообщение от alex_x_x Посмотреть сообщение
CEBEP, стандарт с вами не согласится
В чём конкретно он со мной не согласится? То что эти указатели не объедены массивом это весомый момент, но, думаю, степень гипотетичности всего выражения в целом позволяет закрыть на это глаза, ведь сложение указателей должно будет вернуть указатель который вовсе не обязан иметь смысл как таковой, а лишь должен быть использован как левый аргумент в операции вычитания.
Да и вообще что толку апеллировать к стандарту, если зашла речь о сущности которую он предал анафеме? Я просто хотел заметить что чисто алгебраически такая операция может иметь смысл.
0
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
01.05.2012, 18:24 4
Цитата Сообщение от CEBEP Посмотреть сообщение
В чём конкретно он со мной не согласится? То что эти указатели указывают не объеденные массивом это весомый момент, но, думаю, степень гипотетичности всего выражения в целом позволяет закрыть на это глаза, ведь сложение указателей должно будет вернуть указатель который вовсе не обязан иметь смысл как таковой, а лишь должен быть использован как левый аргумент в операции вычитания.
разность указателей дает тип ptrdiff_t
то что нельзя просто так орудовать с указателями говорит стандарт и эта тема [Задача] Адресная арифметика
1
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
01.05.2012, 18:28 5
может быть и можно было бы второй вариант использовать, но для чего?
для обфускации, чтобы враги дольше код понимали?
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
01.05.2012, 18:45  [ТС] 6
Цитата Сообщение от DU Посмотреть сообщение
для чего?
по моему второй вариант должен выполнятся существенно быстрее
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
01.05.2012, 18:50 7
копеечная оптимизация, да и то не факт. нужно в асм смотреть после компиляции с оптимизацией или замеры делать. в любом случае на производительность программы в целом это врятли повлияет. зато код стал такой хитромудрый, что не каждый его сможет осознать.
0
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
01.05.2012, 18:54 8
Цитата Сообщение от CEBEP Посмотреть сообщение
rightInsert + leftInsert - a;
по угару
если rightInsert и leftInsert у верхней границы адресов, то rightInsert + leftInsert может дать переполнение (на 32битах) и результатом будет невалидный указатель
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
01.05.2012, 18:55  [ТС] 9
Цитата Сообщение от DU Посмотреть сообщение
копеечная оптимизация
Не понимаю попытки доказать что это бессмысленно. Строго говоря, я обратного и не утверждал
Цитата Сообщение от alex_x_x Посмотреть сообщение
результатом будет невалидный указатель
да, я об этом прямо упоминал во втором своём сообщении...
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
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
1500 / 1146 / 165
Регистрация: 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
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
01.05.2012, 19:26 12
Цитата Сообщение от DU Посмотреть сообщение
Кстати, ваш код даже не компилируется в студии.
Ну он и не говорил, что компилируется. Это были размышления на тему "Ах если бы, ах если бы... Не жизнь была, а песня бы..."

Добавлено через 6 минут
Кстати, даже если допустить правильность и полезность подобной конструкции, то сложение указателей всё-равно не нужно.
C++
1
ExpressionEdit* b = rightInsert + (leftInsert - a);
1
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
01.05.2012, 19:26 13
Ну можно тогда вообще так
C++
1
flag ? ( a = b, c = d ) : ( a = d, c = b );
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
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
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
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
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
01.05.2012, 20:15 16
ну да, есть такое. оптимизатор мог бы вообще удалить проверки буля и всего того, что в ифе написано. код стал бы мегаоптимальным .
Возвращаясь к предпосылкам возникновения темы: нехер писать подобного рода оптимизации, даже если они реально более оптимальны. выйгрыш копеечный. главное чтобы код оставался чистым, понимаемым, сопровождаемым. а то ведь если все писать в таком духе, где черт ногу словит, но зато "оптимально" одно случайное преобразование типа (скажем из конст чара в строку) из-за динамического выделения памяти в тыщу раз перекроет все эти потуги ради пары тактов.
Впрочем, до понимания этих вещей нужно еще дорасти. Просто советы не работают. На себе проверено
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
01.05.2012, 20:15  [ТС] 17
Всё таки зря я попытался искать в этой операции практическую суть. И тем не менее, ведь такое поведение связанно как раз с тем, что как такового сложения указателей не происходит.
0
01.05.2012, 20:15
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.05.2012, 20:15
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru