powered by simpleCommunicator - 2.0.58     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Очень интересны нюанс с оператором switch
25 сообщений из 236, страница 7 из 10
Очень интересны нюанс с оператором switch
    #39984634
booby
ВсеРазумный

... код - говнокод без логики

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


Что бы показать что он делает на данный момент. А делает он это, как раз таки не с проста.

Прошу обратить внимания на
Код: plaintext
1.
 switch (ch)



А мы помним что
Код: plaintext
1.
char ch = 'c'; 



И компилятор это знает.

А значит он просто берёт, вырезает всё до - того, что будет использовано вообще в коде..

Таким образом, мы должны обмануть компилятор, и сказать что ты ничего не знаешь, вот таким образом
Код: plaintext
1.
switch (ptr[0]) {



И переписать код, вот таким образом

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
bool testSwitch()
{
    char ch = 'c'; // Или 'a', например.
    char str[] = "bcd";
    char *ptr = str;

    while(((ptr = strchr(ptr, ch)) != nullptr)) {
        switch (ptr[0]) {
            case '\0':
            case 'e':
            case 'f':
            case 'g':
                return false;
        }
    }

    return true;
}




И тогда мы увидим наш asm в виде switch else - if
Код: plaintext
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.
testSwitch():
  sub esp, 28
  mov DWORD PTR [esp+12], 6579042
  lea eax, [esp+12]
.L3:
  sub esp, 8
  push 99
  push eax
  call strchr
  add esp, 16
  test eax, eax
  je .L4
  movzx edx, BYTE PTR [eax]
  test dl, dl
  je .L5
  sub edx, 101
  cmp dl, 2
  ja .L3
.L5:
  xor eax, eax
  add esp, 28
  ret
.L4:
  mov eax, 1
  add esp, 28
  ret

...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984645
ВсеРазумный
То есть теперь, глядя на это... Можно смело покрутить у виска человеку, который говорит что расположение DEFAULT в коде влияет на что - то.

ну вообще default то можно всегда в конец ставить, его место там.
но вот то что перемещение case никак не меняет асм - это странно конечно...
Может потому что мало значений и они типа в кеше помещаются?
Реально пробегать по всему циклу из миллиона значений это какая-то дичь

А если if/elseif/else ?
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984649
Алексей Роза
Может потому что мало значений и они типа в кеше помещаются?


Неа..Как Я говорил раньше, компилятор не глупый... Так что да, он их сам сортирует как ему лучше будет использовать код.

Это в 2020г называется - оптимизацией.

Алексей Роза

Реально пробегать по всему циклу из миллиона значений это какая-то дичь

А если if/elseif/else ?


Если ты напишешь elseif конструкцию. То она будет аналогично со switch и это во всех компиляторах так... Включая Delphi и так далее.

Что бы реально избавиться от этой конструкции, надо использовать goto array pointer
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984650
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby

Если у кого-то есть ссылки на актуальные исходники, например для 8-ки, бросьте пожалуйста ссылку в этот топик.
Глянуть может быть и интересно было бы.

Я поищу в том-же OpenJDK бранч или тег с которого релизилась восьмерка. И можно даже
посмотреть какие были сделаны изменения в HEAD ревизии за прошедшие лет 6.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984653
Алексей Роза,

Компилятор создал дубликат функции

https://godbolt.org/z/zGEb7q

Он понял что ничем не отличается код
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984668
Код: plaintext
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.
ElseIf(int, int):
  mov eax, DWORD PTR [esp+4]
  mov edx, DWORD PTR [esp+8]
  cmp eax, 1
  je .L11
  test eax, eax
  je .L12
  cmp eax, 2
  je .L13
  cmp eax, 3
  jne .L10
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 3
  jmp CaseCall4(int, int)
.L12:
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 0
  jmp CaseCall1(int, int)
.L11:
  mov DWORD PTR [esp+4], 1
  jmp CaseCall2(int, int)
.L10:
  mov eax, 100
  ret
.L13:
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 2
  jmp CaseCall3(int, int)


SwitchElseIf(int, int):
  mov eax, DWORD PTR [esp+4]
  mov edx, DWORD PTR [esp+8]
  cmp eax, 2
  je .L15
  jg .L16
  test eax, eax
  je .L17
  cmp eax, 1
  jne .L14
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 1
  jmp CaseCall2(int, int)
.L16:
  cmp eax, 3
  jne .L14
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 3
  jmp CaseCall4(int, int)
.L15:
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 2
  jmp CaseCall3(int, int)
.L14:
  mov eax, 100
  ret
.L17:
  mov DWORD PTR [esp+8], edx
  mov DWORD PTR [esp+4], 0
  jmp CaseCall1(int, int)



Чёт прожал и не заметил

Там везде по = ровно было
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984670
ВсеРазумный
Неа..Как Я говорил раньше, компилятор не глупый... Так что да, он их сам сортирует как ему лучше будет использовать код.

Это в 2020г называется - оптимизацией.

ок, спрошу по-другому: а почему он ЭТО считает оптимизированным кодом?
Почему перебирать миллион значений каждый раз - это оптимально?
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984674
Алексей Роза,

Потому что это универсально.

К примеру у тебя есть "1, 2, 3, 8343, 9453, 88667" (Уже отсортированный компилятором)

И как ты хочешь, что бы он оптимизировал код, не перебирая ? Ну допустим он возьмёт "1,2,3" и запишет их как goto array pointer
А остальные "8343, 9453, 88667" ему всё равно придётся перепроверить через else-if]


Вот так и выходит, что изначально так и было сделано.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984676
Алексей Роза,

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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
int GetSwitchHashIndex(int i){
  switch(i)
    {
        case 0: return 10;
        case 1: return 20;
        case 55674: return 70;
        case 3453: return 40;
        case 55675: return 50;
    }
}



Но если нарушить порядок, и сделать большие цифры. То мы получим
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
 mov eax, DWORD PTR [esp+4]
  cmp eax, 3453
  je .L9
  jle .L12
  cmp eax, 55674
  mov edx, 70
  mov eax, 50
  cmove eax, edx
  ret
.L12:
  cmp eax, 1
  sbb eax, eax
  and eax, -10
  add eax, 20
  ret
.L9:
  mov eax, 40
  ret
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984677
блин, а что это у вас такое
авторif (i = 1)
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984678
ВсеРазумный
К примеру у тебя есть "1, 2, 3, 8343, 9453, 88667" (Уже отсортированный компилятором)

да не надо мне их сортировать
я знаю, что 8343 случается в 10 раз чаще, и поставил его вперёд.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984680
Алексей Роза,

При этом, если радиус небольшой
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
int GetSwitchHashIndex(int i){
  switch(i)
    {
        case 0: return 10;
        case 1: return 20;
        case 2: return 70;
        case 4: return 40;
        case 8: return 50;
    }
}



после 2 сразу 4 и потом 8 то он увеличивает табоицу массива
Код: plaintext
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.
GetSwitchHashIndex(int):
  mov eax, DWORD PTR [esp+4]
  jmp [DWORD PTR .L9[0+eax*4]]
.L9:
  .long .L13
  .long .L12
  .long .L14
  .long .L8
  .long .L10
  .long .L8
  .long .L8
  .long .L8
  .long .L8
.L10:
  mov eax, 40
  ret
.L14:
  mov eax, 70
  ret
.L13:
  mov eax, 10
  ret
.L8:
  mov eax, 50
  ret
.L12:
  mov eax, 20
  ret





И вот это как раз тот самый случай Goto array to pointer


В таком случае оно работает
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984681
Алексей Роза
ВсеРазумный
К примеру у тебя есть "1, 2, 3, 8343, 9453, 88667" (Уже отсортированный компилятором)

да не надо мне их сортировать
я знаю, что 8343 случается в 10 раз чаще, и поставил его вперёд.


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
int GetSwitchHashIndex(int i){
  switch(i)
    {
        case 55675: return 50;
        case 0: return 10;
        case 1: return 20;
        case 55674: return 70;
        case 3453: return 40;
    }
}



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
GetSwitchHashIndex(int):
  mov eax, DWORD PTR [esp+4]
  cmp eax, 3453
  je .L9
  jle .L12
  cmp eax, 55674
  mov edx, 70
  mov eax, 50
  cmove eax, edx
  ret
.L12:
  cmp eax, 1
  sbb eax, eax
  and eax, -10
  add eax, 20
  ret
.L9:
  mov eax, 40
  ret



Компилятор сам знает. ASM не поменялся, от того что ты поставил выше Ручками.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984683
вот норм порядок и безо всякой компиляторской отсебятины
https://godbolt.org/z/P1Mzxn
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984685
и странно, что "умный компилятор" просто 52 не оставил, ведь там константа в compile-time
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984686
Алексей Роза
и странно, что "умный компилятор" просто 52 не оставил, ведь там константа в compile-time


Она же не inline функция, что бы таким баловаться.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984694
Алексей Роза,

Глянул что там у тебя.

Кстати, умный компилятор Пошёл дальше. И увидел что функция никак не используется. Ничего полезного не делает. И по этому
Код: plaintext
1.
2.
3.
main:
  xor eax, eax
  ret



Пустая процедура main

Код: plaintext
1.
2.
3.
4.
5.
int main()
{
int z = ElseIf(52);
std::cout << z << "!\n";
}




Код: plaintext
1.
2.
  push 52
  call ElseIf(int)



Однако сё работает.

Код: plaintext
1.
int inline ElseIf(int i){



Код: plaintext
1.
2.
3.
4.
5.
  push ecx
  sub esp, 12
  push 57
  push OFFSET FLAT:_ZSt4cout
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984706
Фотография SQL2008
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby
У Кернигана можно найти упоминание о том, произвольность местоположения default была выбрана сознательно ,
в расчете на то, что при возникновении необходимости дописывать что-то в существующий switch,
корпоративные программисты хотели бы и будут размещать новые ветки ниже уже существующих,
а не произвольным образом втыкивать их между старыми, превращая старый код в неузнаваемый.

А куда втискивать новые CASE программистам, которые кодят после программистов, которые уже втыкнули свой код после default?
Мне кажется, что вы просто глумитесь
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984735
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Может быть проще для логики кодо-генерации. Открыть оператор switch() и сразу
бросить дефолтную секцию и потом уже дописывать кейсы по мере поступления
фактов. Как опциональные аргументы. Минус 1 переменная в генераторе.

И по поводу количественных limitations. Тоже ведь никто не гарантирует что код на "C"
писал человек. Вполне может быть продукт biacc/byzon/antlr/Zubr генерации.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984862
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тупанул. Зачем качать когда и так онлайн доступно.

Вобщем вот так лучше

Актуальная версия.

https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/String.java

Версия примерно по релизному тегу JDK-8-b120

https://github.com/openjdk/jdk/blob/9a9add8825a040565051a09010b29b099c2e7d49/jdk/src/share/classes/java/lang/String.java
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984926
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
исходник
Код: plaintext
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.
#include <cstdlib>
#include <cstring>
#include <stdio.h>

using namespace std;

  template <typename T>
  inline __attribute__((always_inline))
  void volatilize(T && ref)
  {
    asm volatile (";\n" : "=m"(ref) : "m"(ref) : );
  }

bool testSwitch
    (
      char   ch,
      int  & count
    )
    noexcept
{
  static const char * str = "abracadabra";
  char * ptr;

  switch (ch)
  {
  default:
    if (nullptr == (ptr = strchr(str, ch)))
  case '\0':
  case 'f':
  case 'j':
  case 's':
      return false;
    else
      count++;
    break;
  }
  return true;
}

int main(int argc, char** argv)
{
  char ch = 'a';
  int count = 0;

  volatilize(ch);
  printf
      (
        "\r\ncount : %i, testSwitch() == %s",
        count,
        testSwitch(ch, count) ? "true" : "false"
      );

  return 0;
}

g++ -m64 -O3 -S -c -std=c++11
(g++.exe (Rev2, Built by MSYS2 project) 9.2.0)

Судя по генерируемому коду, оптимизатор C++ пытается уменьшить количество инструкций перехода. Поэтому в результате получается откровенный маразм, больше похожий на работу какого-нибудь обфускатора.
результат
Код: asm
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.
  .section .rdata,"dr"
.LC0:
  .ascii "abracadabra\0"
  .text
  .p2align 4
  .globl	_Z10testSwitchcRi
  .def	_Z10testSwitchcRi;	.scl	2;	.type	32;	.endef
  .seh_proc	_Z10testSwitchcRi
_Z10testSwitchcRi:
.LFB92:
  pushq	%rbx
  .seh_pushreg	%rbx
  subq	$32, %rsp
  .seh_stackalloc	32
  .seh_endprologue
  movl	%ecx, %eax
  movq	%rdx, %rbx
  testb	%cl, %cl
  je	.L8
  leal	-102(%rcx), %ecx
  cmpb	$13, %cl
  ja	.L5
  movl	$1, %edx
  xorl	%r8d, %r8d
  salq	%cl, %rdx
  testl	$8209, %edx
  jne	.L3
.L5:
  movsbl	%al, %edx
  leaq	.LC0(%rip), %rcx
  call	strchr
  testq	%rax, %rax
  je	.L8
  addl	$1, (%rbx)
  movl	$1, %r8d
.L3:
  movl	%r8d, %eax
  addq	$32, %rsp
  popq	%rbx
  ret
  .p2align 4,,10
  .p2align 3
.L8:
  xorl	%r8d, %r8d
  movl	%r8d, %eax
  addq	$32, %rsp
  popq	%rbx
  ret
  .seh_endproc

...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984936
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devСудя по генерируемому коду, оптимизатор C++ пытается уменьшить количество инструкций перехода.

Ну ты же сам ему сказал оптимизировать на скорость, а переходы плохо сочетаются со
спекулятивным выполнением в процессорах.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984938
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_dev,
Давно известно, что машинные оптимизаторы/генераторы далеки от совершенства.
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984942
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

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

Впечатление у меня такое:
Понятно, что когда-то начиналось с того, что сейчас называют UCS-2.
Потом долепились составные символы и получился UTF-16.
Так как составные символы "практически никому не нужны" и "интерфейс charAt трогать нельзя",
то работа с кодепойнтами прилепилась нашлепкой - "если кому надо, за практическую константу со всем разберутся".

Встретил упоминание занятного документационного бага - исходный код обманка, показывающая "как оно было бы",
если бы на самом деле реализовывалось на java.
Кто-то раскопал, что в каких-то местах исходный код не соответствует работе фактически используемых интризиков, и "хорошо бы поправить".
Не знаю, стали исправлять исходник или нет, лень искать регистрацию этого бага...
...
Рейтинг: 0 / 0
Очень интересны нюанс с оператором switch
    #39984967
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Шипилев ЕМНИП где-то рассказывал зачем нужен код-обманка но честно говоря я не очень запомнил.

Кажется в его докладах по Lord Of String. Или что-то в этом роде.
...
Рейтинг: 0 / 0
25 сообщений из 236, страница 7 из 10
Форумы / C++ [игнор отключен] [закрыт для гостей] / Очень интересны нюанс с оператором switch
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]