C golf için ipuçları


137

C'de golf oynamak için hangi genel ipuçlarınız var? Genel olarak golf problemlerini kodlamak için uygulanabilecek fikirlere bakıyorum (en azından C'ye özgü) (örneğin "yorumları kaldır" bir cevap değildir). Lütfen cevap başına bir ipucu gönderin. Ayrıca, bahşişinizin C89 ve / veya C99 için geçerli olup olmadığını ve yalnızca belirli derleyicilerde çalışıp çalışmadığını lütfen ekleyin.


8
Tek cümlenin en büyük ipucu olduğunu düşünüyorum: IOCCC'ye gönderilen kazanan kodları okuyun.
vsz

Yanıtlar:


107

Tamsayılar arasındaki eşitsizliği kontrol etmek için bit yönünde XOR kullanın:

if(a^b)yerine if(a!=b)1 karakter kaydeder.


73
a-bsana da aynı efekti verir.
ugoren

22
Benzer şekilde a*byerine kullanabilirsiniz a&&b(farklı önceliği vardır, kötü olabilir veya olmayabilir). A / = -b (örneğin a||ba+b
imzasızlar

3
daha iyisi bunu Elvis Operator ile birleştirin ?:(yerine): örneğin farklı olması durumunda bir şey yapması için: a^b?_diff_:;
Olivier Dulac

1
@OlivierDulac Yanlış dallanma durumunda boş bir üçlü kabul eden bir derleyici var mı?
Jonathan Frech

1
@OlivierDulac Kontrol edebilirsiniz. Bildiğim kadarıyla, GCC'nin ?:eşdeğeri olan bir operatör vara ? a : b
Chromium

75
  • mainBir veya daha fazla tam sayı değişkeni bildirmek için kötüye kullanımın tartışma listesi:

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

    ( programlama dillerinde alfabeye cevap )

    Bu çözüm , programın herhangi bir argüman olmadan çağrılması koşuluyla a(aka argc) 'nın başlaması gerçeğini de kötüye kullanır 1.

  • İşleri sıfıra başlatmak için global değişkenleri kullanın:

    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'a cevap ! )


62

Virgül operatörü, parantezlerden kaçınırken tek bir blokta birden fazla ifadeyi yürütmek için kullanılabilir:

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");                                                                     

}

Çıktılar: 1 2


İfadelerden biri işe yaramazsa break.
Maxim Mikhaylov

9
@ MaxLawnboy çünkü breakbir ifadedir ve bu cevap ifadeler hakkında konuşuyor.
NieDzejkob

59

Felaket fonksiyon bağımsız değişken türü bildirimlerinden kaçının

Beş argümanın hepsinin de olduğu bir işlev ilan ediyorsanız int, hayat iyidir. sadece yazabilirsin

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

Ama varsayalım dihtiyaçları olması charbile bir ya int*. O zaman sen battın! Bir parametre türden önce gelirse, tümü şöyle olmalıdır:

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

Fakat bekle! İşe yaramaz karakterlerin bu felaket patlama çevresinde bir yol var. Bu böyle devam ediyor:

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

mainKomut satırı argümanlarını kullanmanız gerekirse , bu standart bir bildirgede bile tasarruf sağlar :

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

iki bayttan daha kısa

main(int c,char**v){

PPCG'de bugüne kadar rastlamadığım için bunu keşfettiğimde şaşırdım.


6
Neden bu işe yarıyor?
Nathaniel

30
Görünüşe göre bu K & R tarzı ve on yıl boyunca ANSI C önce gelir.
Dennis,

K&R özelliklerini ve daha yeni ('99 de ki) özelliklerini birlikte kullanmanın naylon veya mümkün olamayabileceğini unutmayın. Derleyicinize bağlı.
dmckee

5
@dmckee haklı. C99 tam int'e izin vermiyor, bu yüzden kullanmak zorundasın -std=gnu99ve şimdi taşınabilir değilsin. Clc-speak, "C" kodunu bile yazmıyorsunuz, ama "Gnu99-C" yazıyorsunuz. 'Buralarda çoğunlukla bunu görmezden geliyoruz, ancak derleyiciye özel kod gönderirseniz, bunu belirtmekte fayda var. Bazen insanlar aslında do indirip bizim bu programları yürütmek. :)
luser droog

@ lucerdroog: -std=c89Kodunuzu eski uyarıya göre derlemesini sağlamak için gcc veya clang'a anlatmak için kullanabilirsiniz ;
Peter Cordes

37

> = Ve <= yerine, karşılaştırılan değerler sıfırın üzerindeyken tamsayı bölmesini (/) kullanabilirsiniz; bu, bir karakter kaydeder. Örneğin:

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

Tabii ki hala daralan, örneğin sadece> ve ^ (bazı durumlarda && veya || yazmamak için akıllıca bir yöntem) kullanarak.

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

Tamsayı bölme numarası, bir karakterin kaydedildiğinden sayının 100'den az olup olmadığına karar vermek için kullanışlıdır:

a<100 vs 99/a

Bu, aynı zamanda daha yüksek önceliğe ihtiyaç duyulan durumlarda da iyidir.


Sen yazabilirputchar(c>31&c<127?c:46);
Jin X

37

GCC gibi bazı derleyiciler, temel #includes, param ve dönüş türlerini atlamanıza izin verir main.

Aşağıdakiler, GCC ile derleyen (uyarılarla) geçerli bir C89 ve C99 programıdır:

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

#includeFor stdio.h dosyasının eksik olduğuna, dönüş türünün maineksik olduğuna ve tür bildiriminin ieksik olduğuna dikkat edin.


17
Teknik olarak standartlara göre geçerli değildir, çünkü ana sıfır veya iki parametreyi kabul eder, birini değil. Kimsenin kod golfü umurunda değil.
Konrad Borowski

printf()Bir prototip olmadan çağrı yapmak (veya herhangi bir değişken işlev) tanımsız davranışa neden olur . GCC varsayılan olarak standart C'yi derlemez. Gcc'yi C89 modunda ( gcc -ansi -pedantic) veya C99 modunda ( gcc -std=c99 -pedantic) çağırırsanız , en azından ikinci durumda, epeyce şikayetler alacaksınız.
Nisse Engström

@ NisseEngström: ana akım C uygulamalarındaki çağrı kuralları prototipler olmadan değişken işlevlerin çağrılmasını güvenli hale getirir. Bu yüzden çoğu C uygulaması davranışı tanımlar.
Peter Cordes,

29

Üçlü koşullu operatör ?:genellikle basit bir dayanak noktası olarak kullanılabilir if- elsehatırı sayılır tasarruflarla açıklamalar.

C ++ eşdeğerinin aksine , operatör resmen bir değer vermez , ancak bazı derleyiciler (özellikle gcc) bununla kurtulmanıza izin verir, ki bu güzel bir bonus.


Ekleme: Sadece bir ifşa ihtiyacınız varsa, fakat başka bir şeye ihtiyacınız yoksa, o zaman üçlü hâlâ faydalı olabilir.
Casey,

9
&&ve ||ayrıca kullanılabilir: if(x==3)f()Önerinizle birlikte olur x==3?f():0ve daha da geliştirilebilir x==3&&f(). Ancak operatör önceliği konusunda dikkatli olun - eğer f()değiştirilirse y=1, &&çözüm fazladan bir parantez seti gerektirir.
ugoren

1
?:Gcc'nin bir değer verdiğini asla anlamadım. Bunu üretim kodunda kullanabilir miyim? lol
Jeff Burdges

4
@ugoren: x==3&&f()daha golf oynayabilirx^3||f()
fgrieu

@fgrieu, evet, buradaki tam olarak konu olmasa da ( bu cevap bunu öneriyor).
25’de

27

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

Bitler güzel.

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

Fakat farklı önceliklere sahip ve x gibi ++ ve - değişikliklerini yapmayın. Ayrıca bunu gerçekten özel durumlarda kullanabilirsiniz: ~ 9, -10'dan daha kısa.

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

Bu daha ezoteriktir, ama onu kullanma fırsatım oldu. Kısa devre umurunda değilse

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

Ayrıca:

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

5
Son ipucu ( (x/y) == (x>=y)) gerçekten kullanışlıdır.
ugoren

24

Lambda kullan (taşınabilir değil)

Onun yerine

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

veya (yalnızca gcc)

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

veya (blok desteği olan llvm)

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

gibi bir şey dene

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

... burada alıntılanan dize "lambda" fonksiyonunuzun makine dili talimatlarını içerir (tüm platform ABI gereksinimlerine uygundur).

Bu, dize sabitlerinin çalıştırılabilir olarak işaretlendiği ortamlarda çalışır. Varsayılan olarak, bu Linux ve OSX'te geçerlidir ancak Windows'ta geçerlidir.

Kendi "lambda" işlevlerinizi yazmayı öğrenmenin saçma bir yolu, işlevi C'ye yazmak, onu derlemek, benzer bir şeyle incelemek objdump -Dve karşılık gelen hex kodunu bir dizeye kopyalamaktır. Örneğin,

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

... gcc -Os -cLinux için derlendiğinde x86_64 hedefi gibi bir şey üretir

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

GNU CC goto:

Bu "lambda işlevlerini" doğrudan çağırabilirsiniz ancak aradığınız kod parametreleri almazsa ve geri dönmezse, gotobirkaç bayttan tasarruf etmek için kullanabilirsiniz . Yani yerine

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

veya (çevrenizde Arapça glif yoksa)

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

Deneyin

goto*&L"ﻫ";

veya

goto*&L"\xfeeb";

Bu örnekte, eb fex86 makine dili gibi for(;;);bir şeydir ve parametreleri almayan ve geri dönmeyecek olan şeylerin basit bir örneğidir :-)

gotoÇağıran bir ebeveyne dönen kodu girebileceğiniz anlaşılıyor .

#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));
}

Yukarıdaki örnek (Linux ile birlikte derlenip çalıştırılabilir gcc -O) yığın düzenine duyarlıdır.

EDIT: Alet zincirinize bağlı olarak, -zexecstackderleme bayrağını kullanmanız gerekebilir .

Hemen anlaşılmıyorsa, bu cevap esas olarak lols için yazılmıştır. Bunu okumaktan daha iyi veya daha kötü golf oynamaya ya da olumsuz psikolojik sonuçlara karşı sorumluluk almam.


2
Ben sadece standart bir C fonksiyonunun bölümlerini okumak ve bir C lambda yazdırmak için bir komut dosyası yazdım . Cevabınızda söylemeye değer olabilir, sadece bunu yapmayı öğrettiğinizden beri görmeniz iyi olabilir.
MD XF

23

Kullanım imleçlerini yerine işaretçileri. brk()Başlangıçta yakalayın ve temel işaretçi olarak kullanın .

char*m=brk();

Ardından hafıza erişimi için bir # tanım yapın.

#define M [m]

M*tamsayılara uygulanan bir postfix olur . (Eski bir [x] == x [a] numarası.)

Ancak, dahası var! Ardından, işaretçi argümanlarına ve makrolardan daha kısa olan fonksiyonlarda geri dönüşlere sahip olabilirsiniz (özellikle 'return' ifadesini kısaltırsanız):

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

Bir imleci bir imleç yapmak için, taban imlecini çıkartarak, bir int'ye giren bir ptrdiff_t elde edersiniz, kayıplar yer biziz.

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

Bu teknik cevap yazılmamış lambda matematiği için tercüman yazmak için kullanılır .


21

Değişkenler yerine parametreleri tanımlayın.

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

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

İkinci parametreyi gerçekten geçmenize gerek yok.

Ayrıca, parantezi kaydetmek için operatör önceliğini kullanabilirsiniz.
Örneğin, (x+y)*2olabilir x+y<<1.


Ya da sadece x+y*2, başka bir karakter kaydetme.
Braden Best

4
@ B1KMusic, x+y*2operatör önceliği nedeniyle aynı değil.
ugoren

Tamam lol. Bu x + (y * 2) olur. x+y<<1Örnek olarak tespit edildim, olduğu gibi değerlendirildi x+(y<<1)ve *2bunun yerine önerildi . Bitshift operasyonlarının örneğin olarak değerlendirildiğini bilmiyordum(x+y)<<2
Braden Best

20

Genellikle EOF == -1, EOF'yi kontrol etmek için bit yönünde NOT operatörünü kullanın: while(~(c=getchar()))veya while(c=getchar()+1)her yerde c'nin değerini değiştirin.


1
C'yi yeterince iyi tanımıyorum ama while(1+c=getchar())işe yaramayacak mı?
4ı'uʎs

6
@ Hayır. Hayır. Ekleme operatörü +, atama operatöründen daha yüksek önceliğe sahiptir =, bu 1+c=getchar()nedenle eşdeğerdir (1+c)=getchar(), çünkü derleme yapmaz çünkü bir (1+c)değer değildir.
ace_HongKongIndependence

19

Üçlü operatör ?:iki ayrı parçaya sahip olması nedeniyle alışılmadık bir durumdur. Bu nedenle, standart operatör öncelik kurallarına bir boşluk deliği sağlar. Bu parantezleri önlemek için yararlı olabilir.

Aşağıdaki örneği ele alalım:

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

Her zamanki golf yaklaşımı yerini alacak ifolan &&, fakat virgül operatörünün düşük öncelik, parantez fazladan bir çift gerekir:

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

Üçlü operatörün orta bölümünde, parantez gerekmez, ancak:

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

Dizi yorumları için de benzer yorumlar geçerlidir.


7
Bu örnekte, b-=a=bdaha kısadır. İşin ?:püf noktası hala faydalı, -=çünkü aynı zamanda düşük bir tercihe sahip.
ugoren

İyi bir nokta; benim örneğim gereksiz yere karmaşıktı.
breadbox

Başka bir nokta bazen koşulunu çevirmek istediğiniz olmasıdır: için x>0||(y=3), x>0?0:(y=3)işe yaramaz, ama x<1?y=3:0iş yok.
12'de ugoren

Hem clang hem de gcc, üçlüsünde boş bir gerçek olaya izin verir . Belirtilmezse, değeri koşulun değeridir. Örneğin,x>5?:y=1
Chris Uzdavin

19

Kodunuzun birkaç kez tekrarlanan herhangi bir kısmı, ön işlemciyle değiştirilmeye adaydır.

#define R return

Kod, birkaç işlevden fazlasını içeriyorsa, çok yaygın bir kullanım durumudur. Gibi diğer uzunca anahtar kelimeler while, double, switch, ve caseayrıca adaylardır; yanı sıra kodunuzda idomatik olan herhangi bir şey.

Bu amaçla genel olarak büyük harf rezervi tutarım.


1
Daha kısa bir değiştirme olacaktır -DR=return. Belirli karakterleri eklerseniz, tanım etrafında tek veya çift tırnak kullanılması gerekebileceğini unutmayın -DP='puts("hello")'.

15

Programınız her adımda birer birer okuyup yazıyorsa, getchar () ve putchar () yerine her zaman okuma ve yazma işlevini kullanın .

Örnek ( Ters stdin ve stdout'taki yer )

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

Alıştırma: İyi bir skor elde etmek için bu tekniği kullanın burada .


Her adımda ne demek istiyorsun ?
Casey,

Casey: Sanırım programın bir şeyler okuyup okumadığı, üzerinde çalıştığı ve çıktı yazdığı anlamına geliyor. Bir akış şeklinde, demek ki. Tüm girdilerin bir kerede okunup ele alınması gerektiği bir yaklaşımın aksine.
Joey

Joey haklı, ben de aynı anlama geldim, üzgünüm gelen kutuma bugüne kadar bakmadım.
Quixotic

8
Bu yığın manipülasyonu muhteşem.
Andrea Biondo

14

Ters Döngüler

Yapabiliyorsanız, değiştirmeyi deneyin.

for(int i=0;i<n;i++){...}

ile

for(int i=n;i--;){...}


12

Sıfır değerine dönüş değerleri kullanın. Bazı işlevler çağırırsanız ve bu işlev normal koşullar altında sıfır döndürürse, sıfırın beklendiği bir yere yerleştirebilirsiniz. Aynı şekilde, eğer fonksiyonun bir patlama eklenmesiyle sıfırdan dönmeyeceğini biliyorsanız. Ne de olsa, bir kod golfünde her halükarda uygun bir hata işleme yapmazsınız, değil mi?

Örnekler:

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

12

Dönüş yerine atayın.

Bu gerçekten standart C değil, bildiğim her derleyici ve CPU ile çalışıyor:

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

aynı etkiye sahiptir:

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

Çünkü ilk argüman, dönüş değeriyle aynı CPU kaydında saklanır.

Not: Bir yorumda belirtildiği gibi, bu tanımsız bir davranıştır ve her işlem için çalışması garanti edilmez. Ve herhangi bir derleyici optimizasyonu sadece üzerinden atlayacaktır.

X-makrolar

Bir başka kullanışlı özellik: X-Makrolar değişken listeniz olduğunda size yardımcı olabilir ve hepsini içeren bir işlem yapmanız gerekebilir:

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


3
Bunu alıntı yaptım ve düzeltildim, Bu sadece doğru değil. Yalnızca çarpma ve bölmelerle ve optimizasyonlar kapatıldığında çalışır. Bunun nedeni, her iki işlemin de sonuçlarını, geri dönüş için ortak kayıt olan eax'a koymasıdır. Parametreler yığında veya ecx veya edx'te saklanır. Kendin dene.
Gaspa79

3
Haklısın, tanımsız bir davranış, aynı zamanda derleyiciye ve mimariye bağlı, bu hileyi kullanarak herhangi bir cevabı göndermeden önce genellikle x86 ve armv7 ile kontrol ediyorum. Ve tabii ki optimizasyonu etkinleştirirseniz, herhangi bir akıllı derleyici sadece gereksiz çarpmayı siler.
GB

3
Bu çalışmayı GCC ile görmüştüm ama diğerleri ile değil
Albert Renshaw

1
@ Gaspa79: gcc, -O0her zaman, getiri-değer kaydındaki ifadeleri değerlendirmeyi seçer. En azından x86'ya , ARM'e ve MIPS'e baktım ( gcc.godbolt.org'da ) ve gcc de bunu yapmak için kendi yolundan çıktı -O0. Eğer, bu yararlanmak eğer Ama unutmayın siz is içinde programladığınızı dili gcc -O0, değil C değil C, ve buna göre cevap etiketlemelisiniz . -O0Hata ayıklama modu dışında herhangi bir optimizasyon düzeyinde başarısız olur ve clang IIRC ile çalışmaz.
Peter Cordes,

11
  1. Bir dizinin ilk elemanına erişmek *ayerine kullanın a[0].

  2. İlişkisel operatörler ( !=, >vb.) 0Veya verir 1. Bunu, koşulun doğru ya da yanlış olmasına bağlı olarak farklı ofsetler vermek için aritmetik işleçlerle kullanın: eğer varsa ve a[1+2*(i<3)]erişecekti .a[1]i >= 3a[3]


11
a[i<3?3:1]iki karakterden kısa a[1+2*(i<3)].
Reto Koradi

10

IOCCC arşivlerine bakabilirsiniz (uluslararası karışık C kod yarışması).

Dikkate değer bir hile, genişlemesi dengesiz ayraçlar / parantezler gibi makroları tanımlamaktır.

#define P printf(

16
Uyumsuz parantezlerin kendi içinde hiçbir değeri yoktur. Mesele, mümkün olduğu kadar tekrar eden modelin çoğunu tanımlamaktır. İle daha ileri gitmek isteyebilirsiniz #define P;printf(.
12'de ugoren

Bu kısaltılmış bayt nasıl sayılır? Belki bir örnek verelim?
Cyoce

2
@Cyoce Örneğin, bu cevaba bakınız .
Jonathan Frech

8

for(int i=0;i<n;i++){a(i);b(i);} birkaç yolla kısaltılabilir:

for(int i=0;i<n;){a(i);b(i++);}Döngüdeki ++sonuncuya gitmek için -1i

for(int i=0;i<n;b(i++))a(i); -3 hariç tüm ifadeleri ana döngünün üst ve dışına taşımak için


Virgül operatörünü kullanmak, bazı durumlarda diş tellerinden kaçınmanın başka bir yoludur.
Peter Cordes,

8

İşlevsel ol!

Sorununuzu aynı imzayla basit işlevlere azaltabilir ve tek ifadeler olarak #define r returntanımlayabiliyorsanız, bir işlevi tanımlamak için neredeyse tüm plakanın tümünden daha iyi ve çarpan çıkarabilirsiniz .

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

Program sonucu, işletim sistemine döndürülen durum değeridir veya kabuk veya IDE'yi kontrol eder.

Kullanma __VA_ARGS__, bu işlev ifadelerinde dizi noktaları eklemek için virgül operatörünü kullanmanızı sağlar . Bu gerekli değilse, makro daha kısa olabilir.

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

7
  1. scanf("%*d ");kukla girişi okumak için kullanın . (girişin daha sonraki programlarda anlamsız olması durumunda), scanf("%d",&t);t değişkenini bildirmeniz gerekenden daha kısadır .

  2. int dizisine karakter kaydetmek karakter dizisinden çok daha iyidir. örnek.

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


2
Aslında, %*dsadece Golf'te kullanmıyorum, çünkü örneğin birinin yeni bir satır atlamak isteyeceği durumlarda da kullanışlıdır scanf("%[^\n]%*c",str);:)
Aralık'ta

6

Bir karakter yazdırın ve yerine satırbaşını yerleştirin:

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

veya

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

basitçe, c'yi bir int olarak ilan edin ve:

puts(&c);

9
Muhtemelen bunun küçük bir endian mimarisine bağlı olduğunu belirtmekte fayda var. C büyük endian int ise, o zaman sadece satır başı alırsınız. (Öte yandan, eğer c bir karakter ise, bir satır başı yerine rastgele çöp elde edebilirsiniz.)
breadbox

@breadbox evet, tamamen haklısın; Yeni düzenleme yaptım: son alıntı c'yi int olarak kullanmalı (bu şekilde bildirilmesi genellikle kolaydır).
moala

Mu puts(&c)gerçekten işe? Bu mutlaka boş bırakılamaz.
Esolanging Fruit

1
@EsolangingFruit 32-bit girişli küçük endianda, int 0 ≤ c <256 bayt dizisi c 0 0 0 olarak kaydedilir . Adresini tercüman zaman c olarak char *karakter: biz tekil dizesini görmek c , null byte izledi.
Dennis

6

Kullanmak asprintf(), açık bir şekilde dize uzunluğunu ölçmek ve aynı zamanda ölçme char*! Bu, kod golf oynamak için fazla faydalı olmayabilir, ancak günlük çalışmalarını bir karakter dizisi ile kolaylaştırır. 21. Yüzyıl C’de bazı daha iyi tavsiyeler var .

Kullanım örneği:

#define _GNU_SOURCE
#include <stdio.h>

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

6

import Eğer zorundaysan

İlk cevapta belirtildiği gibi , bazı derleyiciler (özellikle, GCC ve clang) #includestandart kütüphane fonksiyonları için ihmal etmekten kaçınmanıza izin verir .

Sadece onu kaldıramasanız bile #include, bundan kaçınmanın başka yolları olabilir , ancak bu her zaman pratik ya da özellikle golf değildir.

Kalan durumlarda, bir bayt kaydetmek #import<header file>yerine kullanabilirsiniz #include<header file>. Bu bir GNU uzantısıdır ve kullanımdan kaldırıldığı kabul edilir, ancak en azından gcc 4.8, gcc 5.1 ve clang 3.7'de çalışır.


6

Deneyin cpow()yerinecos()

Onun yerine

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

gibi bir şey dene

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

Bu Euler formülünü kullanır , biraz karmaşık bir analiz yapar ve bir kompleksi ikiye bölüştüren gözlem gerçek kısmı verir (değişken işlev çağrıları ve diğer incelikler ile dikkatli).

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

Bu tür bir hile azaltmak için kullanılabilir

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

içine

double y=cpow(1i,x);

Çünkü (1) ^ \ frac {x} {2} = j ^ {\ frac {2x} {2}} = j ^ x


5

İşte benim avantajım için kullandığım birkaç ipucu. Onları utanmadan başkalarından çaldım, bu yüzden benden başkasına kredi:

İşlev çağrıları ile atamayı birleştir

Bunun yerine:

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

Bunu yap:

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

Birden fazla değişkeni birlikte başlat (mümkün olduğunda)

Bunun yerine:

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

Bunu yap:

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

Sıfır / sıfır olmayan değerleri daralt

Buradaki birinden aldığım düzgün bir numara (kim olduğunu unutma, üzgünüm). Bir tamsayı değerine sahipseniz ve onu 1 veya 0 değerine daraltmanız gerektiğinde, bunu !!kolayca yapabilirsiniz. Bu bazen gibi diğer alternatifler için avantajlıdır ?:.

Bu durumu al:

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

Bunun yerine bunu yapabilirsiniz:

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

Başka bir örnek:

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

Olarak yeniden yazılabilir:

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

1
belkiR*-~!!mxxxx
l4m2

5

Temel mantıksal eşitlikleri bilmek bir kaç bayt tasarruf edebilir. Örneğin, if (!(a&&b)){}DeMorgan yasasını kullanmak yerine, deneyin if (!a||!b){}. Yerine: aynı işlevleri Bitsel için de geçerlidir ~(a|b)do ~a&~b.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.