Поради щодо гольфу в С


137

Які загальні поради щодо гольфу в С? Я шукаю ідеї, які можна застосувати до проблем із гольфом взагалі, які принаймні дещо характерні для C (наприклад, "видалити коментарі" - це не відповідь). Будь ласка, опублікуйте одну пораду за кожну відповідь. Також, будь ласка, включіть, якщо ваша порада стосується C89 та / або C99 і якщо вона працює лише на певних компіляторах.


8
Я думаю, що найбільший односкладний натяк: Прочитайте виграшні коди, подані до МОКК.
vsz

Відповіді:


107

Використовуйте бітовий XOR для перевірки нерівності між цілими числами:

if(a^b)замість if(a!=b)збереження 1 символу.


73
a-bдає такий же ефект.
ugoren

22
Аналогічно ви можете використовувати a*bзамість a&&b(має різну перевагу, може бути, а може і не погано). Якщо ви знаєте a / = -b (наприклад, вони не підписані), тоді a||b==a+b
пройдіть

3
краще все ж поєднувати його з Оператором Елвіса ?:(замість if): для приклад просто робити щось, якщо інше: a^b?_diff_:;
Олів'є Дулак

1
@OlivierDulac Чи є компілятор, який приймає порожню потрійну, якщо помилкова гілка?
Джонатан Фрех

1
@OlivierDulac Ви можете перевірити. З того, що мені відомо, GCC має ?:оператора, який є рівнозначнимa ? a : b
Chromium

75
  • Зловживання mainсписком аргументів для оголошення однієї чи кількох цілих змінних:

    main(a){for(;++a<28;)putchar(95+a);}
    

    (відповідь на алфавіт на мовах програмування )

    Це рішення також зловживає тим, що a(ака argc) починається як 1, за умови, що програма викликається без аргументів.

  • Використовуйте глобальні змінні, щоб ініціалізувати речі до нуля:

    t[52],i;main(c){for(;i<52;)(c=getchar())<11?i+=26:t[i+c-97]++;
    for(i=27;--i&&t[i-1]==t[i+25];);puts(i?"false":"true");}
    

    (відповідь на Anagram Code Golf! )


62

Оператор з комами може використовуватися для виконання декількох виразів в одному блоці, уникаючи дужок:

main(){                                                                                     

int i = 0;                                                                                  
int j = 1;                                                                                  
if(1)                                                                                       
    i=j,j+=1,printf("%d %d\n",i,j); // multiple statements are all executed                                                  
else                                                                                        
    printf("failed\n");                                                                     

}

Виходи: 1 2


Не працює, якщо є одне з тверджень break.
Максим Михайлов

9
@MaxLawnboy тому break, що це твердження, і ця відповідь говорить про вирази.
NieDzejkob

59

Уникайте катастрофічних оголошень типу аргументів

Якщо ви оголошуєте функцію, де всі п’ять аргументів ints, то життя - це добре. можна просто написати

f(a,b,c,d,e){

Але припустимо , що dпотреби бути char, або навіть int*. Тоді ви накрутили! Якщо одному параметру передує тип, всі вони повинні бути:

f(int a,int b,int c,int*d,int e){

Але зачекайте! Існує шлях до цього згубного вибуху марних персонажів. Виходить так:

f(a,b,c,d,e) int *d; {

Це навіть економить на стандартній mainдекларації, якщо вам потрібно використовувати аргументи командного рядка:

main(c,v)char**v;{

на два байти коротше, ніж

main(int c,char**v){

Я був здивований, коли виявив це, оскільки досі не стикався з цим на PPCG.


6
Чому на Землі це працює ??
Натаніел

30
Мабуть, це називається стилем K&R, і це передує ANSI C на десятиліття.
Денніс

Зауважте, що використання функцій K&R та новіших (скажімо, '99) функцій разом є, або це не можливо. Залежить від вашого компілятора.
dmckee

5
@dmckee має рацію. C99 не дозволяє неявний int, тому вам доведеться користуватися, -std=gnu99і тепер ви не портативний. Якщо ви говорите на CLC, ви навіть не пишете код "C" як такий, але "Gnu99-C". "Тут ми здебільшого ігноруємо це, але добре згадати про це, якщо ви розміщуєте код, який відповідає компілятору. Іноді люди на самому ділі зробити для завантаження і виконання цих програм у нас. :)
luser droog

@luserdroog: Ви можете -std=c89сказати gcc або clang, щоб компілювати свій код відповідно до того старшого стандарту, який дозволяє неявний int лише з попередженням.
Пітер Кордес

37

Замість> = і <= ви можете просто використовувати ціле ділення (/), коли порівняні значення вище нуля, що зберігає один символ. Наприклад:

putchar(c/32&&126/c?c:46); //Prints the character, but if it is unprintable print "."

Що, звичайно, все-таки скорочується, використовуючи, наприклад, просто> і ^ (розумний спосіб уникнути написання && або || в деяких випадках).

putchar(c>31^c>126?c:46);

Приміром поділу на ціле число, наприклад, корисно вирішити, чи є число менше 100, оскільки це зберігає символ:

a<100 vs 99/a

Це добре також у випадках, коли потрібен більший пріоритет.


Можна написатиputchar(c>31&c<127?c:46);
Jin X

37

Деякі компілятори, такі як GCC, дозволяють опустити базові #includeтипи s, param та return для main.

Далі йдеться про дійсну програму C89 та C99, яка компілює (з попередженнями) з GCC:

main(i) { printf("%d", i); }

Зауважте, що #includeдля stdio.h відсутній, тип повернення для mainвідсутній, а декларація типу для iвідсутня.


17
Технічно це не відповідає стандартам, оскільки main приймає нуль або два параметри, а не один. Не те, що когось хвилює код гольфу.
Конрад Боровський

Виклик printf()(або будь-яка різноманітна функція) без прототипу викликає не визначену поведінку . GCC не компілює стандартний C за замовчуванням. Якщо ви попросите gcc в режимі C89 ( gcc -ansi -pedantic) або режимі C99 ( gcc -std=c99 -pedantic), ви отримаєте досить багато скарг, принаймні в останньому випадку.
Nisse Engström

@ NisseEngström: умовні виклики в основних реалізаціях C дозволяють безпечно викликати різні функції без прототипів. Тож більшість C-реалізацій визначають поведінку.
Пітер Кордес

29

Потрійний умовний оператор ?:часто може бути використаний як опозиція для простих if- elseзаяв із значною економією.

На відміну від еквівалента c ++, оператор формально не дає значення lvalue , але деякі компілятори (особливо gcc) дозволять вам уникнути цього, що є приємним бонусом.


Доповнення: Якщо вам потрібен лише ін, але не інший, то потрійний все ще може бути корисним.
Кейсі

9
&&а ||також може бути використаний: if(x==3)f()стає за вашою пропозицією x==3?f():0, і може бути вдосконалений до x==3&&f(). Але будьте обережні з перевагою оператора - якщо f()його замінити y=1, то для &&вирішення потрібен додатковий набір дужок.
ugoren

1
Я ніколи не усвідомлював, що gcc ?:приносить вагоме значення. Чи можу я використовувати це у виробничому коді? lol
Jeff Burdges

4
@ugoren: x==3&&f()можна продовжити гольф доx^3||f()
fgrieu

@fgrieu, так, хоча тут це не зовсім тема ( ця відповідь пропонує це).
угорен

27

http://graphics.stanford.edu/~seander/bithacks.html

Шматочки приємні.

~-x = x - 1
-~x = x + 1

Але з різними пріоритетами, і не змінюйте x, як ++ і -. Також ви можете використовувати це в дійсно конкретних випадках: ~ 9 коротше, ніж -10.

if(!(x&y)) x | y == x ^ y == x + y
if(!(~x&y)) x ^ y == x - y

Це більш езотерично, але я мав привід використовувати його. Якщо вас не хвилює коротке замикання

x*y == x && y
if(x!=-y) x+y == x || y

Також:

if(x>0 && y>0) x/y == x>=y   

5
Остання порада ( (x/y) == (x>=y)) дійсно корисна.
угорен

24

Використовуйте лямбда (не повідомляється)

Замість

f(int*a,int*b){return*a>*b?1:-1;}
...
qsort(a,b,4,f);

або (лише gcc)

qsort(a,b,4,({int L(int*a,int*b){a=*a>*b?1:-1;}L;}));

або (llvm з підтримкою блоків)

qsort_b(a,b,4,^(const void*a,const void*b){return*(int*)a>*(int*)b?1:-1;});

спробуйте щось подібне

qsort(a,b,4,"\x8b\7+\6\xc3");

... де цитується рядок містить машинні інструкції вашої функції "лямбда" (відповідно до всіх вимог ABI платформи).

Це працює в середовищах, у яких рядкові константи позначені як виконувані. За замовчуванням це справедливо в Linux та OSX, але не в Windows.

Один нерозумний спосіб навчитися писати власні функції "лямбда" - це написати функцію на C, компілювати її, оглянути її з чимось на зразок objdump -Dта скопіювати відповідний шістнадцятковий код у рядок. Наприклад,

int f(int*a, int*b){return *a-*b;}

... при компіляції з gcc -Os -cдля цілі Linux x86_64 генерує щось подібне

0:   8b 07                   mov    (%rdi),%eax
2:   2b 06                   sub    (%rsi),%eax
4:   c3                      retq

GNU CC goto:

Ви можете викликати ці "лямбда-функції" безпосередньо, але якщо код, який ви викликаєте, не приймає параметри і не збирається повертатися, ви можете використовувати gotoдля збереження кількох байт. Тож замість

((int(*)())L"ﻫ")();

або (якщо у вашому оточенні немає арабських гліфів)

((int(*)())L"\xfeeb")();

Спробуйте

goto*&L"ﻫ";

або

goto*&L"\xfeeb";

У цьому прикладі, eb feце машинна мова x86 для чогось подібного for(;;);і є простим прикладом того, що не приймає параметри і не збирається повертати :-)

Виявляється, ви можете gotoкодувати, який повертається до виклику батьків.

#include<stdio.h>
int f(int a){
 if(!a)return 1;
 goto*&L"\xc3c031"; // return 0;
 return 2; // never gets here
}
int main(){
 printf("f(0)=%d f(1)=%d\n",f(0),f(1));
}

Вищеописаний приклад (може компілюватися та працювати в Linux з gcc -O) чутливий до макета стека.

EDIT: Залежно від вашої ланцюжка інструментів, можливо, вам доведеться використовувати -zexecstackпрапор компіляції.

Якщо це не відразу зрозуміло, ця відповідь була написана в основному для лолів. Я не несу відповідальності за кращий чи гірший гольф чи несприятливі психологічні наслідки, читаючи це.


2
Я щойно написав сценарій, щоб прочитати частини функції C зі стандартного в та надрукувати C лямбда. Можливо, варто згадати у своїй відповіді, можливо, вам би було приємно бачити, оскільки ви навчили мене це робити в першу чергу.
MD XF

23

Використовуйте курсори замість покажчиків. Зачепіть brk()на початку і використовуйте його як базовий покажчик .

char*m=brk();

Потім зробіть #define для доступу до пам'яті.

#define M [m]

Mстає постфіксом, *застосованим до цілих чисел. (Старий фокус [x] == x [a].)

Але, є більше! Тоді ви можете мати вказівні аргументи та повернення у функціях, коротших за макроси (особливо якщо скорочено "return"):

f(x){return x M;} //implicit ints, but they work like pointers
#define f(x) (x M)

Щоб зробити курсор з вказівника, ви віднімаєте базовий покажчик, отримуючи ptrdiff_t, який скорочується до int, втрати - це yer biz.

char *p = sbrk(sizeof(whatever)) - m;
strcpy(m+p, "hello world");

Ця методика використовується в моїй відповіді Написати перекладача для нетипового обчислення лямбда .


21

Визначте параметри замість змінних.

f(x){int y=x+1;...}

f(x,y){y=x+1;...}

Фактично не потрібно передавати другий параметр.

Також ви можете використовувати пріоритет оператора для збереження дужок.
Наприклад, (x+y)*2може стати x+y<<1.


Або просто x+y*2, заощадивши ще одне чародійство.
Бреден Кращий

4
@ B1KMusic, x+y*2не те саме, через перевагу оператора.
угорен

Правильно, хаха. Це було б x + (y * 2). Я фіксувався на x+y<<1прикладі, припускаючи, що його оцінюють як x+(y<<1), і запропонував *2натомість. Я не знав, що операції по переміщенню в біт змінюються як наприклад(x+y)<<2
Braden Best

20

Оскільки зазвичай EOF == -1, використовуйте побітовий оператор NOT, щоб перевірити наявність EOF: while(~(c=getchar()))або while(c=getchar()+1)змінити значення c у кожному місці


1
Я не знаю С досить добре, але не while(1+c=getchar())працював би ?
ɐɔıʇǝɥʇuʎs

6
@ ɐɔıʇǝɥʇuʎs Ні. Оператор додавання +має більший пріоритет, ніж оператор присвоєння =, тому 1+c=getchar()еквівалентний (1+c)=getchar(), який не компілюється, оскільки (1+c)не є значенням.
ace_HongKongIndependence

19

Потрійний оператор ?:незвичайний тим, що має дві окремі частини. Через це він забезпечує трохи лазівки до стандартних правил пріоритетності оператора. Це може бути корисно для уникнення дужок.

Візьмемо такий приклад:

if (t()) a = b, b = 0;  /* 15 chars */

Звичайна гра в гольф підхід полягає в заміні ifз &&, але через низький пріоритету оператора кома, вам потрібна додаткова пара дужок:

t() && (a = b, b = 0);  /* still 15 chars */

Середній розділ потрійного оператора не потребує дужок:

t() ? a = b, b = 0 : 0;  /* 14 chars */

Подібні коментарі стосуються підписок масиву.


7
У цьому прикладі b-=a=bще коротше. ?:Трюк ще корисно, -=тому що також має низьке перевагу.
угорен

Влучне зауваження; мій приклад був марно складним.
хлібниця

Ще один момент полягає в тому, що іноді потрібно перевернути умову: бо x>0||(y=3), x>0?0:(y=3)це марно, але x<1?y=3:0робить роботу.
угорен

і clang, і gcc дозволяють порожній справжній випадок у трійці. Якщо пропущено, його значення - це значення умови. Наприклад,x>5?:y=1
Кріс Уздавініс

19

Будь-яка частина вашого коду, яка повторюється кілька разів, є кандидатом на заміну попереднього процесора.

#define R return

- дуже поширений випадок використання, якщо код включає в себе більше ніж пару функцій. Інші довгі ключові слова , такі як while, double, switch, і caseтакож є кандидатами; а також все, що у вашому коді ідентичне.

Зазвичай я зарезервую великі символи для цієї мети.


1
Коротша заміна була б -DR=return. Зауважте, що якщо ви включите певні символи, може виникнути необхідність мати окремі або подвійні лапки навколо визначення -DP='puts("hello")'.

15

Якщо ваша програма читає чи пише по одному на кожному етапі, завжди намагайтеся використовувати функцію читання і запису замість getchar () та putchar () .

Приклад ( Зворотний stdin та місце на stdout )

main(_){write(read(0,&_,1)&&main());}

Вправа: Використовуйте цю техніку, щоб отримати хороший бал тут .


Що ви маєте на увазі під кожним етапом ?
Кейсі

Кейсі: Я думаю, вони означають, що програма щось читає, оперує нею і пише вихід. Потоково, так би мовити. На відміну від підходу, коли всі дані повинні бути прочитані та оброблені одразу.
Joey

Джої має рацію, я мав на увазі те саме, вибачте, що не перевірив папку "Вхідні" до сьогодні.
Кіхотик

8
Ця маніпуляція стеком є ​​чудовою.
Андреа Біондо


13

Якщо вам коли-небудь потрібно вивести один символ нового рядка ( \n), не використовуйте putchar(10), не використовуйте puts("").


12

Використовуйте значення повернення до нуля. Якщо ви викликаєте якусь функцію, і ця функція повертає нуль у звичайних умовах, ви можете розмістити її в місці, де очікується нуль. Так само якщо ви знаєте, функція поверне не нульову, з додаванням чубчика. Зрештою, ви ні в якому разі не робите належних помилок у коді гольфу, правда?

Приклади:

close(fd);foo=0;   →  foo=close(fd);    /* saves two bytes */
putchar(c);bar=0;  →  bar=!putchar(c);  /* saves one byte  */

12

Призначити замість повернення.

Це насправді не стандартний C, але працює з кожним компілятором і процесором, про які я знаю:

int sqr(int a){return a*a;}

має такий же ефект, як:

int sqr(int a){a*=a;}

Тому що перший аргумент зберігається в тому ж регістрі процесора, що і повернене значення.

Примітка. Як зазначається в одному коментарі, це не визначене поведінка і не гарантується для кожної операції. І будь-яка оптимізація компілятора просто пропустить її.

X-макроси

Ще одна корисна особливість: X-Macros може допомогти вам, коли у вас є список змінних, і вам потрібно виконати деяку операцію, яка включає в себе всі:

https://en.wikipedia.org/wiki/X_Macro


3
Я цитував це, і мене виправили. Це просто неправда. Він працюватиме лише з множеннями та діленнями та тоді, коли оптимізація буде вимкнена. Це відбувається тому, що обидві операції ставлять свої результати в eax, що є загальним реєстром повернення. Параметри зберігаються або в стеці, або в exx, або в edx. Спробуйте самі.
Gaspa79

3
Ви маєте рацію, це невизначена поведінка, це також залежить від компілятора та архітектури, я зазвичай перевіряю з gcc на x86 та armv7, перш ніж публікувати будь-яку відповідь за допомогою цього фокусу. І звичайно, якщо ввімкнути оптимізацію, будь-який розумний компілятор просто видалить непотрібне множення.
ГБ

3
Я бачив цю роботу з GCC, але не з іншими
Альберт Реншо

1
@ Gaspa79: gcc з -O0завжди вибирає для оцінки виразів у регістрі повернених значень. Я придивився до x86, ARM та MIPS принаймні (на gcc.godbolt.org ), і gcc, здається, вийшов зі свого шляху, щоб це зробити -O0. Але пам'ятайте , якщо ви скористатися цим, мова програмування ви в є gcc -O0, НЕ C , і ви повинні маркувати свою відповідь відповідно, а НЕ C . Він виходить з ладу на будь-якому рівні оптимізації, окрім -O0режиму налагодження, і не працює з clang IIRC.
Пітер Кордес

11
  1. Використовуйте *aзамість a[0]для доступу до першого елемента масиву.

  2. Реляційні оператори ( !=, >тощо) дають 0або 1. Використовуйте це з арифметичними операторами, щоб надати різні зсуви залежно від того, чи умова є істинною чи помилковою: a[1+2*(i<3)]матиме доступ, a[1]якщо i >= 3та a[3]інше.


11
a[i<3?3:1]на два символи коротше a[1+2*(i<3)].
Рето Коради

10

Ви можете заглянути в архіви МОКЦ (міжнародний конкурс з прихованим кодом C).

Один помітний трюк - це #define макроси, розширення яких має незбалансовані дужки / дужки, як-от

#define P printf(

16
Невідповідні дужки не мають значення самі по собі. Суть у тому, щоб визначити якомога більше повторюваних шаблонів. Можливо, ви захочете піти далі, с #define P;printf(.
угорен

Як цей короткий байт рахується? Можливо, наведіть приклад?
Cyoce

2
@Cyoce Дивіться, наприклад, цю відповідь .
Джонатан Фрех

8

for(int i=0;i<n;i++){a(i);b(i);} можна скоротити кількома способами:

for(int i=0;i<n;){a(i);b(i++);} -1 для переміщення ++останнього iв циклі

for(int i=0;i<n;b(i++))a(i); Ще 3 для переміщення всіх, окрім однієї заяви, у верхню та основну петлю, зняття дужок


Використання оператора комами - це ще один спосіб уникнути дужок у деяких випадках.
Пітер Кордес

8

Ідіть функціонально!

Якщо ви можете звести свою проблему до простих функцій з однаковою підписом і визначених як одиночні вирази, то ви можете зробити краще #define r returnі розмежувати майже всю плиту котла для визначення функції.

#define D(f,...)f(x){return __VA_ARGS__;}
D(f,x+2)
D(g,4*x-4)
D(main,g(4))

Результатом програми є її значення статусу, повернене в ОС або керуючу оболонку або IDE.

Використання __VA_ARGS__дозволяє використовувати оператор комами для введення точок послідовності в ці вирази функцій . Якщо це не потрібно, макрос може бути коротшим.

#define D(f,b)f(x){return b;}

7
  1. використовувати scanf("%*d ");для читання вхідних даних. (у випадку, якщо введення в подальшій програмі безглуздо) воно коротше, ніж scanf("%d",&t);там, де також потрібно оголосити змінну t.

  2. зберігання символів у масиві int набагато краще, ніж масив символів. приклад.

    s[],t;main(c){for(scanf("%*d ");~(c=getchar());s[t++]=c)putchar(s[t]);}


2
Насправді я використовую %*dне лише гольф, тому що це також корисно в ситуаціях, коли, наприклад, хотілося б пропустити новий рядок scanf("%[^\n]%*c",str);:)
tomsmeding

6

Роздрукуйте символ, а потім поверніть каретку замість:

printf("%c\n",c);

або

putchar(c);putchar('\n'); // or its ascii value, whatever!

просто, оголосити c як int і:

puts(&c);

9
Напевно, варто зазначити, що це залежить від малоіндійської архітектури. Якщо c - інт-ендіан, то ви просто отримаєте повернення вагона. (З іншого боку, якщо c - знак, ви можете отримати випадкове сміття після повернення вагона.)
хлібниця

@breadbox так, ви абсолютно праві; Я щойно відредагував: останній уривок повинен використовувати c як int (що часто легко оголосити таким).
моала

Чи puts(&c)справді працює? Це не обов'язково припиняється до нуля.
Esolanging Fruit

1
@EsolangingFruit На маленькому ендіані з 32-бітовими входами int 0 ≤ c <256 зберігається як послідовність байтів c 0 0 0 . Інтерпретуючи адресу c як char *, ми бачимо однотонний рядок: символ c , а за ним - нульовий байт.
Денніс

6

Використання asprintf()заощаджує чітке виділення, а також вимірювання довжини рядка ака char*! Це може бути не надто корисно для гольф-коду, але полегшує повсякденну роботу з масивами чарів. Є ще кілька хороших порад у 21-му столітті .

Приклад використання:

#define _GNU_SOURCE
#include <stdio.h>

int main(int argc, char** argv) {
  char* foo;
  asprintf(&foo, "%s", argv[1]);
  printf("%s",foo);
}

6

import якщо вам доведеться

Як зазначається в першій відповіді , деякі компілятори (зокрема, GCC і clang) дозволяють вам уникнути пропуску #includes для стандартних функцій бібліотеки.

Навіть якщо ви не можете просто вийняти це #include, можуть бути й інші способи уникнути цього , але це не завжди практично або особливо гостро.

В інших випадках ви можете використовувати #import<header file>замість того, #include<header file>щоб зберегти байт. Це розширення GNU, і воно вважається застарілим, але воно працює принаймні у gcc 4.8, gcc 5.1 та clang 3.7.


6

Спробуйте cpow()замістьcos()

Замість

double y=cos(M_PI*2*x);

спробуйте щось подібне

double y=cpow(-1,x*2);

Для цього використовується формула Ейлера , трохи складний аналіз та зауваження, що присвоєння комплексу подвійному дає реальну частину (обережно з викликами різних функцій та іншими тонкощами).

\ cos 2 \ pi x + j \ sin 2 \ pi x = e ^ {j2 \ pi x} = e ^ {j \ pi 2x} = (- 1) ^ {2x}

Цей тип трюку можна використовувати для зменшення

double y=cpow(-1,x/2);

в

double y=cpow(1i,x);

оскільки (-1) ^ \ frac {x} {2} = j ^ {\ frac {2x} {2}} = j ^ x


5

Ось кілька порад, які я використав на свою користь. Я безсоромно вкрав їх у інших, так що заслуга будь-кого, крім мене:

Поєднайте призначення з викликами функцій

Замість цього:

r = /* Some random expression */
printf("%d", r);

Зробити це:

printf("%d", r = /* Some random expression */);

Ініціалізуйте кілька змінних разом (коли це можливо)

Замість цього:

for(i=0,j=0;...;...){ /* ... */ }

Зробити це:

for(i=j=0;...;...){ /* ... */ }

Згорнути нульові / ненульові значення

Це акуратний трюк, який я зібрав у когось тут (не пам'ятаю кого, вибачте). Якщо у вас є ціле значення, і вам потрібно згорнути його до 1 або 0, ви можете використовувати !!це легко. Це іноді вигідно для інших альтернатив, таких як ?:.

Скористайтеся цією ситуацією:

n=2*n+isupper(s[j])?1:0; /* 24 */

Ви можете замість цього зробити:

n=n*2+!!isupper(s[j]); /* 22 */

Ще один приклад:

r=R+(memcmp(b+6,"---",3)?R:0); /* 30 */

Можна переписати як:

r=R+R*!!memcmp(b+6,"---",3)); /* 29 */

1
можливоR*-~!!mxxxx
l4m2

5

Знаючи основні логічні рівності, можливо, вдасться зберегти пару байтів. Наприклад, замість того, щоб if (!(a&&b)){}спробувати замість цього використовувати закон DeMorgan if (!a||!b){}. Те саме стосується і побітових функцій: замість ~(a|b)виконання ~a&~b.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.