Tips untuk bermain golf di C

137

Apa tips umum yang Anda miliki untuk bermain golf di C? Saya mencari ide yang dapat diterapkan pada masalah kode golf secara umum yang setidaknya agak spesifik untuk C (mis. "Hapus komentar" bukan jawaban). Silakan kirim satu tip per jawaban. Juga, harap sertakan jika tip Anda berlaku untuk C89 dan / atau C99 dan jika itu hanya bekerja pada kompiler tertentu.

Casey
sumber
8
Saya pikir petunjuk satu kalimat terbesar adalah: Baca kode pemenang yang diserahkan ke IOCCC.
vsz

Jawaban:

107

Gunakan bitwise XOR untuk memeriksa ketimpangan antar integer:

if(a^b)bukannya if(a!=b)menyimpan 1 karakter.

Lowjacker
sumber
73
a-bmemberi Anda efek yang sama.
ugoren
22
Demikian pula Anda dapat menggunakan a*bsebagai gantinya a&&b(memiliki prioritas berbeda, mungkin atau mungkin tidak buruk). Jika Anda tahu a / = -b (misalnya mereka tidak ditandai) maka a||b==a+b
walpen
3
lebih baik lagi menggabungkannya dengan Operator Elvis ?:(bukan jika): untuk contoh hanya melakukan sesuatu jika berbeda: a^b?_diff_:;
Olivier Dulac
1
@OlivierDulac Apakah ada kompiler yang menerima terner kosong jika cabang palsu?
Jonathan Frech
1
@OlivierDulac Anda dapat memeriksa. Dari yang saya tahu, GCC memiliki ?:operator yang setara dengana ? a : b
Chromium
75
  • mainDaftar argumen penyalahgunaan untuk mendeklarasikan satu atau lebih variabel integer:

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

    (jawaban untuk Alfabet dalam bahasa pemrograman )

    Solusi ini juga menyalahgunakan fakta bahwa a(alias argc) dimulai sebagai 1, asalkan program dipanggil tanpa argumen.

  • Gunakan variabel global untuk menginisialisasi hal ke nol:

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

    (jawaban untuk Golf Kode Anagram! )

Joey Adams
sumber
62

Operator koma dapat digunakan untuk mengeksekusi banyak ekspresi dalam satu blok sekaligus menghindari kawat gigi:

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

}

Output: 1 2

Casey
sumber
Tidak berfungsi jika salah satu pernyataannya adalah break.
Maxim Mikhaylov
9
@ MaxLawnboy karena breakpernyataan, dan jawaban ini berbicara tentang ekspresi.
NieDzejkob
59

Hindari deklarasi tipe argumen fungsi-bencana

Jika Anda mendeklarasikan fungsi di mana kelima argumen adalah ints, maka hidup itu baik. Anda cukup menulis

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

Tetapi anggaplah dperlu menjadi char, atau bahkan sebuah int*. Maka Anda kacau! Jika satu parameter didahului oleh suatu tipe, semuanya harus:

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

Tapi tunggu! Ada cara di sekitar ledakan bencana karakter yang tidak berguna ini. Bunyinya seperti ini:

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

Ini bahkan menghemat maindeklarasi standar jika Anda perlu menggunakan argumen baris perintah:

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

dua byte lebih pendek dari

main(int c,char**v){

Saya terkejut menemukan ini, karena sejauh ini saya belum menemukannya di PPCG.

feersum
sumber
6
Mengapa di bumi ini bekerja ??
Nathaniel
30
Rupanya ini disebut gaya K&R dan mendahului ANSI C selama satu dekade.
Dennis
Perhatikan bahwa menggunakan fitur K&R dan fitur yang lebih baru (katakan '99) bersama-sama tidak atau tidak mungkin dilakukan. Tergantung pada kompiler Anda.
dmckee
5
@ dmckee benar. C99 tidak mengizinkan int implisit, jadi Anda harus menggunakan -std=gnu99dan sekarang Anda tidak portabel. Di CLC-Speak, Anda bahkan tidak menulis kode "C", tetapi "Gnu99-C". 'Sekitar sini kita sebagian besar mengabaikan itu, tetapi ada baiknya menyebutkannya jika Anda memposting kode yang spesifik compiler. Terkadang orang benar - benar mengunduh dan menjalankan program-program kita ini. :)
luser droog
@luserdroog: Anda dapat menggunakan -std=c89untuk memberitahu gcc atau dentang untuk mengkompilasi kode Anda sesuai dengan standar yang lebih lama, yang memungkinkan int implisit hanya dengan peringatan.
Peter Cordes
37

Alih-alih> = dan <= Anda cukup menggunakan pembagian integer (/) ketika nilai yang dibandingkan di atas nol, yang menyimpan satu karakter. Sebagai contoh:

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

Yang tentu saja masih menyusut, misalnya menggunakan hanya> dan ^ (cara cerdas untuk menghindari penulisan && atau || dalam beberapa kasus).

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

Trik pembagian integer misalnya berguna untuk memutuskan apakah angka kurang dari 100, karena ini menyimpan karakter:

a<100 vs 99/a

Ini juga baik dalam kasus-kasus ketika prioritas lebih tinggi diperlukan.

Untuk S
sumber
Anda dapat menulisputchar(c>31&c<127?c:46);
Jin X
37

Kompiler tertentu, seperti GCC, memungkinkan Anda untuk menghilangkan #includetipe dasar , param, dan mengembalikan main.

Berikut ini adalah program C89 dan C99 yang valid yang mengkompilasi (dengan peringatan) dengan GCC:

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

Perhatikan bahwa #includeuntuk stdio.h hilang, jenis kembalinya untuk mainhilang, dan deklarasi tipe untuk ihilang.

Casey
sumber
17
Secara teknis itu tidak sah menurut standar karena utama menerima nol atau dua parameter, bukan satu. Bukan berarti siapa pun peduli dengan kode golf.
Konrad Borowski
Memanggil printf()(atau fungsi variadik apa pun) tanpa prototipe menyebabkan perilaku yang tidak terdefinisi . GCC tidak mengkompilasi standar C secara default. Jika Anda memanggil gcc dalam mode C89 ( gcc -ansi -pedantic) atau mode C99 ( gcc -std=c99 -pedantic), Anda akan mendapatkan beberapa keluhan, setidaknya dalam kasus terakhir.
Nisse Engström
@ NisseEngström: konvensi pemanggilan implementasi C mainstream membuatnya aman untuk memanggil fungsi variadic tanpa prototipe. Jadi sebagian besar implementasi C mendefinisikan perilaku.
Peter Cordes
29

Operator kondisional terner ?:sering dapat digunakan sebagai berdiri di untuk sederhana if- elsepernyataan di tabungan yang cukup.

Berbeda dengan c ++ , operator tidak secara formal menghasilkan nilai , tetapi beberapa kompiler (terutama gcc) akan membiarkan Anda melakukannya, yang merupakan bonus yang bagus.

dmckee
sumber
Tambahan: Jika Anda hanya membutuhkan jika, tetapi bukan yang lain maka ternary masih bisa berguna.
Casey
9
&&dan ||juga dapat digunakan: if(x==3)f()menjadi dengan saran Anda x==3?f():0, dan dapat lebih ditingkatkan x==3&&f(). Tapi hati-hati dengan prioritas operator - jika f()diganti dengan y=1, maka &&solusinya memerlukan kurung tambahan.
ugoren
1
Saya tidak pernah menyadari bahwa gcc ?:menghasilkan nilai yang tinggi. Bisakah saya menggunakannya dalam kode produksi? lol
Jeff Burdges
4
@ugoren: x==3&&f()bisa bermain golf lebih lanjut kex^3||f()
fgrieu
@ fgrieu, ya, meskipun itu bukan topik di sini ( jawaban ini menyarankan itu).
ugoren
27

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

Bit itu bagus.

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

Tetapi dengan presedensi yang berbeda, dan jangan ubah x seperti ++ dan -. Anda juga dapat menggunakan ini dalam kasus yang sangat spesifik: ~ 9 lebih pendek dari -10.

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

Itu lebih esoteris, tetapi saya punya kesempatan untuk menggunakannya. Jika Anda tidak peduli tentang hubungan arus pendek

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

Juga:

if(x>0 && y>0) x/y == x>=y   
walpen
sumber
5
Tip terakhir ( (x/y) == (x>=y)) sangat berguna.
ugoren
24

Gunakan lambdas (tidak dapat diangkut)

Dari pada

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

atau (hanya gcc)

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

atau (llvm dengan dukungan balok)

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

coba sesuatu seperti

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

... di mana string yang dikutip berisi instruksi bahasa mesin dari fungsi "lambda" Anda (sesuai dengan semua persyaratan platform ABI).

Ini berfungsi di lingkungan di mana konstanta string ditandai dapat dieksekusi. Secara default ini benar di Linux dan OSX tetapi tidak di Windows.

Salah satu cara konyol untuk belajar menulis fungsi "lambda" Anda sendiri adalah menulis fungsi dalam C, mengompilasinya, memeriksanya dengan sesuatu seperti objdump -Ddan menyalin kode hex yang sesuai ke dalam sebuah string. Sebagai contoh,

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

... ketika dikompilasi dengan gcc -Os -cuntuk target Linux x86_64 menghasilkan sesuatu seperti

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

GNU CC goto:

Anda dapat memanggil "fungsi lambda" ini secara langsung tetapi jika kode yang Anda panggil tidak mengambil parameter dan tidak akan kembali, Anda dapat menggunakan gotountuk menyimpan beberapa byte. Jadi, bukannya

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

atau (jika lingkungan Anda tidak memiliki mesin terbang Arab)

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

Mencoba

goto*&L"ﻫ";

atau

goto*&L"\xfeeb";

Dalam contoh ini, eb feadalah bahasa mesin x86 untuk sesuatu seperti for(;;);dan merupakan contoh sederhana dari sesuatu yang tidak mengambil parameter dan tidak akan kembali :-)

Ternyata Anda bisa gotokode yang kembali ke induk panggilan.

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

Contoh di atas (mungkin dikompilasi dan dijalankan di Linux dengan gcc -O) sensitif terhadap tata letak tumpukan.

EDIT: Bergantung pada rantai alat Anda, Anda mungkin harus menggunakan -zexecstackflag kompilasi.

Jika tidak segera terlihat, jawaban ini terutama ditulis untuk lol. Saya tidak bertanggung jawab untuk bermain golf yang lebih baik atau lebih buruk atau hasil psikologis yang merugikan dari membaca ini.

plafon
sumber
2
Saya baru saja menulis sebuah skrip untuk membaca bagian-bagian dari fungsi C dari standar dan mencetak C lambda. Mungkin layak disebutkan dalam jawaban Anda, mungkin lebih baik bagi Anda untuk melihat sejak Anda mengajari saya untuk melakukan ini sejak awal.
MD XF
23

Gunakan kursor bukan pointer. Rebut brk()di awal dan gunakan sebagai basis-pointer .

char*m=brk();

Kemudian buat #define untuk akses memori.

#define M [m]

Mmenjadi postfix yang *diterapkan ke bilangan bulat. (Trik [x] == x [a] lama.)

Tapi, masih ada lagi! Kemudian Anda bisa memiliki pointer pointer dan mengembalikan fungsi yang lebih pendek dari makro (terutama jika Anda menyingkat 'return'):

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

Untuk membuat kursor dari sebuah pointer, Anda mengurangi pointer-basis, menghasilkan ptrdiff_t, yang memotong menjadi int, kerugian adalah milik Anda.

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

Teknik ini digunakan dalam jawaban saya untuk Menulis penerjemah untuk kalkulus lambda yang tidak diketik .

luser droog
sumber
21

Tentukan parameter, bukan variabel.

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

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

Anda tidak perlu melewati parameter kedua.

Anda juga dapat menggunakan prioritas operator untuk menyimpan tanda kurung.
Misalnya (x+y)*2bisa jadi x+y<<1.

ugoren
sumber
Atau hanya x+y*2, menyimpan lagi arang.
Braden Best
4
@ B1KMusic, x+y*2tidak sama, karena prioritas operator.
ugoren
Benar, lol. Itu akan menjadi x + (y * 2). Saya terpaku pada x+y<<1contoh, dengan asumsi itu sedang dievaluasi x+(y<<1), dan menyarankan yang *2sebaliknya. Saya tidak tahu operasi bitshift dievaluasi sebagai contoh(x+y)<<2
Braden Best
20

Karena biasanya EOF == -1, gunakan operator bitwise TIDAK untuk memeriksa EOF: while(~(c=getchar()))atau while(c=getchar()+1)dan memodifikasi nilai c di setiap tempat

Lowjacker
sumber
1
Saya tidak tahu C cukup baik, tetapi tidak akan while(1+c=getchar())berhasil?
4ıʇǝɥʇu
6
@ No.ıʇǝɥʇu. Tidak. Operator penjumlahan +memiliki prioritas lebih tinggi daripada operator penugasan =, sehingga 1+c=getchar()setara dengan (1+c)=getchar(), yang tidak dikompilasi karena (1+c)bukan nilai.
ace_HongKongIndependence
19

Operator ternary ?:tidak biasa karena memiliki dua bagian yang terpisah. Karena itu, ini memberikan sedikit celah untuk aturan prioritas operator standar. Ini berguna untuk menghindari tanda kurung.

Ambil contoh berikut:

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

Pendekatan golf yang biasa adalah untuk mengganti ifdengan &&, tetapi karena prioritas rendah dari operator koma, Anda memerlukan sepasang tanda kurung tambahan:

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

Bagian tengah operator ternary tidak membutuhkan tanda kurung, meskipun:

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

Komentar serupa berlaku untuk subscript array.

kotak roti
sumber
7
Dalam contoh ini, b-=a=bbahkan lebih pendek. The ?:trick masih membantu, -=karena juga memiliki preferensi yang rendah.
ugoren
Poin bagus; teladan saya tidak perlu rumit.
kotak roti
Poin lain adalah bahwa kadang-kadang Anda ingin membalik kondisi: karena x>0||(y=3), x>0?0:(y=3)tidak berguna, tetapi x<1?y=3:0melakukan pekerjaan.
ugoren
baik dentang dan gcc memungkinkan kasus benar kosong di ternary. Jika dihilangkan, nilainya adalah nilai kondisi. Misalnya,x>5?:y=1
Chris Uzdavinis
19

Bagian mana pun dari kode Anda yang berulang beberapa kali adalah kandidat untuk penggantian dengan pra-prosesor.

#define R return

adalah kasus penggunaan yang sangat umum jika kode Anda melibatkan lebih dari beberapa fungsi. Kata kunci gondrong lainnya seperti while, double, switch, dan casejuga calon; serta segala sesuatu yang idomatis dalam kode Anda.

Saya biasanya memesan karakter huruf besar untuk tujuan ini.

dmckee
sumber
1
Penggantian yang lebih pendek adalah -DR=return. Perhatikan bahwa jika Anda memasukkan karakter tertentu, mungkin perlu memiliki tanda kutip tunggal atau ganda di sekitar define -DP='puts("hello")'.
15

Jika program Anda membaca atau menulis pada satu di setiap langkah dasar selalu mencoba menggunakan fungsi baca dan tulis alih-alih getchar () dan putchar () .

Contoh ( Membalikkan stdin dan menempatkan pada stdout )

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

Latihan: Gunakan teknik ini untuk mendapatkan skor yang bagus di sini .

Pemurah
sumber
Apa yang Anda maksudkan dalam setiap langkah dasar ?
Casey
Casey: Saya kira maksud mereka jika program membaca sesuatu, mengoperasikannya, dan menulis output. Secara streaming, bisa dikatakan. Berbeda dengan pendekatan di mana semua input harus dibaca dan ditangani sekaligus.
Joey
Joey benar, maksud saya sama, maaf saya tidak memeriksa kotak masuk saya sampai hari ini.
Quixotic
8
Manipulasi tumpukan itu bagus sekali.
Andrea Biondo
14

Membalikkan loop

Jika Anda bisa, coba ganti

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

dengan

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

Jika Anda perlu mengeluarkan satu karakter baris baru ( \n), jangan gunakan putchar(10), gunakan puts("").

ace_HongKongIndependence
sumber
12

Manfaatkan nilai kembali ke nol hal. Jika Anda memanggil beberapa fungsi, dan fungsi itu mengembalikan nol dalam kondisi normal, maka Anda dapat menempatkannya di lokasi di mana nol diharapkan. Begitu juga jika Anda tahu fungsinya akan kembali non-nol, dengan tambahan bang. Bagaimanapun, Anda tidak melakukan penanganan kesalahan yang tepat dalam kode golf dalam hal apa pun, bukan?

Contoh:

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

Tetapkan alih-alih kembali.

Ini sebenarnya bukan C standar, tetapi bekerja dengan setiap kompiler dan CPU yang saya tahu:

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

memiliki efek yang sama dengan:

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

Karena argumen pertama disimpan ke register CPU yang sama dengan nilai pengembalian.

Catatan: Seperti disebutkan dalam satu komentar, ini adalah perilaku yang tidak terdefinisi dan tidak dijamin bekerja untuk setiap operasi. Dan setiap optimasi kompiler hanya akan melewatinya.

X-Macro

Fitur lain yang bermanfaat: X-Macro dapat membantu Anda ketika Anda memiliki daftar variabel dan Anda perlu melakukan beberapa operasi yang melibatkan semuanya:

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

GB
sumber
3
Saya mengutip ini dan saya dikoreksi, Ini tidak benar. Ini hanya akan bekerja dengan multiplikasi dan divisi dan ketika optimasi dimatikan. Ini karena kedua operasi kebetulan menempatkan hasilnya di eax yang merupakan register umum untuk pengembalian. Parameter disimpan baik di stack atau ecx atau edx. Cobalah sendiri.
Gaspa79
3
Anda benar, itu perilaku yang tidak terdefinisi, itu juga tergantung pada kompiler dan pada arsitektur, saya biasanya memeriksa dengan gcc pada x86 dan armv7 sebelum memposting jawaban apa pun menggunakan trik ini. Dan tentu saja jika Anda mengaktifkan optimasi, kompiler pintar apa pun hanya akan menghapus perkalian yang tidak perlu.
GB
3
Saya telah melihat pekerjaan ini dengan GCC tetapi tidak pada yang lain
Albert Renshaw
1
@ Gaspa79: gcc dengan -O0selalu memilih untuk mengevaluasi ekspresi dalam register nilai-kembali. Saya telah melihat x86, ARM, dan MIPS setidaknya (di gcc.godbolt.org ), dan gcc tampaknya berusaha keras untuk melakukannya di -O0. Tapi ingat jika Anda mengambil keuntungan dari ini, bahasa yang Anda pemrograman di yaitu gcc -O0, tidak C , dan Anda harus label jawaban Anda sesuai, bukan sebagai C . Gagal pada level optimasi apa pun selain -O0mode debug, dan tidak berfungsi dengan clang IIRC.
Peter Cordes
11
  1. Gunakan *aalih-alih a[0]untuk mengakses elemen pertama array.

  2. Operator relasional ( !=, >, dll) memberikan 0atau 1. Gunakan ini dengan operator aritmatika untuk memberikan offset yang berbeda tergantung pada apakah kondisinya benar atau salah: a[1+2*(i<3)]akan mengakses a[1]jika i >= 3dan a[3]sebaliknya.

es1024
sumber
11
a[i<3?3:1]dua karakter lebih pendek dari a[1+2*(i<3)].
Reto Koradi
10

Anda dapat melihat arsip IOCCC (kontes kode C internasional yang dikaburkan).

Salah satu trik penting adalah #define macro yang ekspansi nya memiliki kurung kurawal / kurung yang tidak seimbang

#define P printf(
Andreas Krey
sumber
16
Kurung yang tidak cocok tidak memiliki nilai dalam dirinya sendiri. Intinya adalah mendefinisikan sebanyak mungkin pola yang berulang. Anda mungkin ingin melangkah lebih jauh, dengan #define P;printf(.
ugoren
Bagaimana cara mempersingkat byte ini? Mungkin memberikan contoh?
Cyoce
2
@Cyoce Lihat misalnya jawaban ini .
Jonathan Frech
8

for(int i=0;i<n;i++){a(i);b(i);} dapat dibuat lebih pendek beberapa cara:

for(int i=0;i<n;){a(i);b(i++);} -1 untuk memindahkan ++ke yang terakhir idalam loop

for(int i=0;i<n;b(i++))a(i); -3 lagi untuk memindahkan semua kecuali satu pernyataan ke atas dan keluar dari loop utama, menghapus kawat gigi

MegaTom
sumber
Menggunakan operator koma adalah cara lain untuk menghindari kawat gigi dalam beberapa kasus.
Peter Cordes
8

Bersikap fungsional!

Jika Anda dapat mengurangi masalah Anda menjadi fungsi-fungsi sederhana dengan tanda tangan yang sama dan didefinisikan sebagai ekspresi tunggal, maka Anda dapat melakukan lebih baik daripada #define r returndan memfaktorkan hampir semua boilerplate untuk mendefinisikan suatu fungsi.

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

Hasil program adalah nilai statusnya dikembalikan ke OS atau mengendalikan shell atau IDE.

Menggunakan __VA_ARGS__memungkinkan Anda untuk menggunakan operator koma untuk memperkenalkan titik-titik urutan dalam ekspresi fungsi ini . Jika ini tidak diperlukan, makro bisa lebih pendek.

#define D(f,b)f(x){return b;}
luser droog
sumber
7
  1. gunakan scanf("%*d ");untuk membaca input dummy. (Dalam hal input tidak berarti dalam program lebih lanjut) itu lebih pendek daripada di scanf("%d",&t);mana Anda juga perlu mendeklarasikan variabel t.

  2. menyimpan karakter dalam array int jauh lebih baik daripada array karakter. contoh.

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

Neeraj Gupta
sumber
2
Sebenarnya, saya menggunakan %*dtidak hanya dalam Golf karena itu juga berguna dalam situasi di mana seseorang akan, misalnya, ingin melewatkan baris baru di scanf("%[^\n]%*c",str);:)
tomsmeding
6

Cetak karakter lalu carriage return, alih-alih:

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

atau

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

sederhana, nyatakan c sebagai int dan:

puts(&c);
moala
sumber
9
Mungkin perlu ditunjukkan bahwa ini tergantung pada arsitektur little-endian. Jika c adalah int big-endian, maka Anda hanya akan mendapatkan carriage return. (Di sisi lain, jika c adalah char, Anda mungkin mendapatkan sampah acak setelah ganti carriage return.)
breadbox
@boxbox ya, Anda sepenuhnya benar; Saya baru saja mengedit: kutipan terakhir harus menggunakan c sebagai int (yang sering mudah dinyatakan seperti itu).
moala
Apakah ini puts(&c)bekerja? Itu tidak harus diakhiri dengan nol.
Buah Esolanging
1
@EsolangingFruit Pada little-endian dengan int 32-bit, int 0 ≤ c <256 disimpan sebagai urutan byte c 0 0 0 . Ketika menafsirkan alamat c sebagai char *, kita melihat string tunggal: karakter c , diikuti oleh byte nol.
Dennis
6

Menggunakan asprintf()menghemat alokasi eksplisit dan juga mengukur panjang string alias char*! Ini mungkin tidak terlalu berguna untuk kode golf, tetapi memudahkan pekerjaan sehari-hari dengan array arang. Ada menyarankan beberapa lebih baik dalam abad ke-21 C .

Contoh penggunaan:

#define _GNU_SOURCE
#include <stdio.h>

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

import jika kamu harus

Seperti disebutkan dalam jawaban pertama , beberapa kompiler (terutama, GCC dan dentang) memungkinkan Anda untuk menghilangkan #includes untuk fungsi perpustakaan standar.

Sekalipun Anda tidak bisa begitu saja melepasnya #include, mungkin ada cara lain untuk menghindarinya , tetapi itu tidak selalu praktis atau khususnya golf.

Dalam kasus yang tersisa, Anda dapat menggunakan #import<header file>alih-alih #include<header file>menyimpan byte. Ini adalah ekstensi GNU dan dianggap sudah usang, tetapi berfungsi setidaknya di gcc 4.8, gcc 5.1, dan clang 3.7.

Dennis
sumber
6

Coba cpow()alih-alihcos()

Dari pada

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

coba sesuatu seperti

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

Ini menggunakan rumus Euler , analisis kompleks kecil dan pengamatan yang menetapkan kompleks untuk menghasilkan ganda bagian nyata (hati-hati dengan panggilan fungsi variadic dan seluk-beluk lainnya).

cos2πx+jsin2πx=ej2πx=ejπ2x=(1)2x

Trik jenis ini dapat digunakan untuk mengurangi

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

ke

double y=cpow(1i,x);

(1)x2=j2x2=jx

LATEX

plafon
sumber
5

Berikut adalah beberapa tips yang saya gunakan untuk keuntungan saya. Saya tanpa malu-malu mencuri mereka dari orang lain, jadi kredit untuk siapa pun kecuali saya:

Gabungkan tugas dengan panggilan fungsi

Alih-alih ini:

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

Melakukan hal ini:

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

Inisialisasi beberapa variabel secara bersamaan (bila mungkin)

Alih-alih ini:

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

Melakukan hal ini:

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

Ciutkan nilai nol / bukan nol

Ini adalah trik rapi yang saya ambil dari seseorang di sini (tidak ingat siapa, maaf). Ketika Anda memiliki nilai integer dan Anda perlu menciutkannya menjadi 1 atau 0, Anda bisa menggunakannya !!untuk melakukannya dengan mudah. Ini kadang menguntungkan untuk alternatif lain seperti ?:.

Ambil situasi ini:

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

Anda bisa melakukan ini:

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

Contoh lain:

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

Dapat ditulis ulang sebagai:

r=R+R*!!memcmp(b+6,"---",3)); /* 29 */
Cole Cameron
sumber
1
mungkinR*-~!!mxxxx
l4m2
5

Mengetahui persamaan logis dasar mungkin dapat menyimpan beberapa byte. Misalnya, alih- if (!(a&&b)){}alih coba gunakan hukum DeMorgan if (!a||!b){}. Hal yang sama berlaku untuk fungsi bitwise: alih-alih ~(a|b)melakukannya ~a&~b.

tox123
sumber
Lih Hukum De Morgan .
Jonathan Frech