답변:
비트 XOR을 사용하여 정수 사이의 불평등을 확인하십시오.
if(a^b)
대신 if(a!=b)
1자를 저장합니다.
a-b
같은 효과를줍니다.
a*b
대신 사용할 수 있습니다 a&&b
(우선 순위가 다르거 나 나쁘거나 나쁘지 않을 수 있음). 만약 당신이 / = -b를 알고 있다면 (예를 들어, 부호가 없다) a||b
==a+b
?:
(대신 경우의) : exemple를 위해 뭔가를 할 수있는 경우의 differents : a^b?_diff_:;
?:
연산자가 있습니다.a ? a : b
main
하나 이상의 정수 변수를 선언하기위한 인수 목록을 남용 하십시오.
main(a){for(;++a<28;)putchar(95+a);}
( 프로그래밍 언어의 알파벳에 대한 답변 )
이 솔루션은 또한 프로그램이 인수없이 호출 되면 a
(일명 argc
)로 시작 한다는 사실을 남용합니다 1
.
전역 변수를 사용하여 사물을 0으로 초기화하십시오.
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");}
( 아나그램 코드 골프에 대한 답변 ! )
쉼표 연산자를 사용하여 중괄호를 피하면서 단일 블록에서 여러 표현식을 실행할 수 있습니다.
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
.
break
는 진술 이므로이 답변은 표현식에 대해 이야기합니다.
다섯 개의 인수가 모두있는 함수를 선언하면 int
인생이 좋습니다. 당신은 단순히 쓸 수 있습니다
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;{
2 바이트보다 짧다
main(int c,char**v){
나는 지금까지 PPCG에서 그것을 발견하지 못했기 때문에 이것을 발견하는 것에 놀랐습니다.
-std=gnu99
하며 이제 이식성이 없습니다. clc-speak에서는 "C"코드 자체를 작성하지 않고 "Gnu99-C"를 작성하고 있습니다. '라운드에서 우리는 대부분 그것을 무시하지만 컴파일러 특정 코드를 게시하는 경우 언급하는 것이 좋습니다. 때때로 사람들은 실제로 않습니다 다운로드하고 우리의이 프로그램을 실행합니다. :)
-std=c89
gcc 또는 clang에게 이전 표준에 따라 코드를 컴파일하도록 지시하면 경고만으로 암시적인 int를 허용합니다.
> = 및 <= 대신에 비교 된 값이 0보다 큰 경우 정수 나누기 (/)를 사용하면 한 문자가 저장됩니다. 예를 들면 다음과 같습니다.
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);
GCC와 같은 특정 컴파일러를 사용하면에 대한 기본 #include
, 매개 변수 및 반환 유형 을 생략 할 수 있습니다 main
.
다음은 GCC를 사용하여 경고와 함께 컴파일하는 유효한 C89 및 C99 프로그램입니다.
main(i) { printf("%d", i); }
것을 알 #include
STDIO.H이 누락에 대한, 대한 반환 형식 main
이 없습니다, 그리고에 대한 형식 선언이 i
없습니다.
printf()
프로토 타입없이 호출 (또는 모든 가변 함수)하면 정의되지 않은 동작이 발생 합니다. GCC는 기본적으로 표준 C를 컴파일하지 않습니다. C89 모드 ( gcc -ansi -pedantic
) 또는 C99 모드 ( gcc -std=c99 -pedantic
) 에서 gcc를 호출 하면 적어도 후자의 경우 상당히 많은 불만이 발생합니다.
삼항 조건 연산자는 ?:
종종 단순한를위한에서 스탠드로 사용할 수 있습니다 if
- else
상당한 비용 절감에서 문.
c ++와 달리 연산자 는 공식적으로 lvalue를 산출하지 않지만 일부 컴파일러 (특히 gcc)를 사용하면 얻을 수 없으므로 좋은 보너스입니다.
&&
그리고 ||
또한 사용할 수 있습니다 if(x==3)f()
귀하의 제안으로되고 x==3?f():0
, 추가로 개선 될 수있다 x==3&&f()
. 그러나 연산자 우선 순위에주의하십시오- f()
로 대체 y=1
하면 &&
솔루션에 추가 괄호 세트가 필요합니다.
?:
가 lvalue를 산출 한다는 것을 결코 깨닫지 못했다 . 프로덕션 코드에서 사용할 수 있습니까? lol
x==3&&f()
더 골프를하실 수 있습니다x^3||f()
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
(x/y) == (x>=y)
)이 정말 유용합니다.
대신에
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");
인용 된 문자열에는 "lambda"기능의 기계 언어 명령어가 포함됩니다 (모든 플랫폼 ABI 요구 사항을 준수 함).
이것은 문자열 상수가 실행 가능한 것으로 표시되는 환경에서 작동합니다. 기본적으로 이것은 Linux 및 OSX에서는 사실이지만 Windows에서는 그렇지 않습니다.
"lambda"함수를 작성하는 방법을 배우는 한 가지 어리석은 방법은 C로 함수를 작성하고, 컴파일하고, 비슷한 것으로 검사하고 objdump -D
, 해당 16 진 코드를 문자열로 복사하는 것입니다. 예를 들어
int f(int*a, int*b){return *a-*b;}
... gcc -Os -c
리눅스 x86_64 대상 용으로 컴파일하면
0: 8b 07 mov (%rdi),%eax
2: 2b 06 sub (%rsi),%eax
4: c3 retq
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
)는 스택 레이아웃에 민감합니다.
편집 : 툴 체인에 따라 -zexecstack
컴파일 플래그 를 사용해야 할 수도 있습니다 .
그것이 명백하지 않은 경우,이 대답은 주로 lols를 위해 작성되었습니다. 나는 이것을 읽음으로써 더 나은 또는 더 나쁜 골프 또는 불리한 심리적 결과에 대해 책임을지지 않습니다.
포인터 대신 커서 를 사용하십시오 . brk()
시작 부분을 잡고 기본 포인터 로 사용하십시오 .
char*m=brk();
그런 다음 메모리 액세스를 위해 #define을 만드십시오.
#define M [m]
M
*
정수에 적용 되는 접미사가 됩니다. (오래된 a [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");
이 기술은 대답하지 않은 람다 미적분에 대한 통역사 를 작성하는 데 사용됩니다 .
변수 대신 매개 변수를 정의하십시오.
f(x){int y=x+1;...}
f(x,y){y=x+1;...}
실제로 두 번째 매개 변수를 전달할 필요는 없습니다.
또한 연산자 우선 순위를 사용하여 괄호를 저장할 수 있습니다.
예를 들어, (x+y)*2
될 수 있습니다 x+y<<1
.
x+y*2
또 다른 문자를 저장합니다.
x+y*2
은 연산자 우선 순위로 인해 동일하지 않습니다.
x+y<<1
평가되었다고 가정 하고 예제를 고쳤 x+(y<<1)
으며 *2
대신 제안했습니다 . 나는 비트 시프트 연산이 예를 들어 평가되었다는 것을 몰랐다(x+y)<<2
일반적으로 EOF == -1
비트 NOT 연산자를 사용하여 EOF를 확인 while(~(c=getchar()))
하거나 while(c=getchar()+1)
모든 위치에서 c 값을 수정하십시오.
while(1+c=getchar())
작동 하지 않습니까?
+
할당 연산자보다 우선 순위가 높기 =
때문에, 1+c=getchar()
동등 (1+c)=getchar()
때문에있는 컴파일되지 않고, (1+c)
좌변이 아니다.
삼항 연산자 ?:
는 두 개의 분리 된 부분이 있다는 점에서 특이합니다. 이 때문에 표준 운영자 우선 순위 규칙에 약간의 허점을 제공합니다. 괄호를 피하는 데 유용 할 수 있습니다.
다음 예제를 보자.
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 */
배열 첨자에도 비슷한 설명이 적용됩니다.
b-=a=b
훨씬 짧습니다. ?:
트릭은 여전히 유용 -=
도 낮은 우선 순위를 가지고 있기 때문이다.
x>0||(y=3)
, x>0?0:(y=3)
쓸모가 없지만, x<1?y=3:0
작업을 수행합니다.
x>5?:y=1
프로그램이 각 단계마다 하나씩 읽거나 쓰는 경우 항상 getchar () 및 putchar () 대신 read 및 write 함수 를 사용하십시오 .
예 ( stdin을 뒤집고 stdout에 배치 )
main(_){write(read(0,&_,1)&&main());}
연습 :이 기술을 사용하여 좋은 점수를 얻으 십시오 .
혹시 출력에 하나의 개행 문자가 필요하면 ( \n
), 사용하지 않는 putchar(10)
, 사용 puts("")
.
이것은 실제로 표준 C는 아니지만 내가 아는 모든 컴파일러 및 CPU에서 작동합니다.
int sqr(int a){return a*a;}
다음과 같은 효과가 있습니다.
int sqr(int a){a*=a;}
첫 번째 인수는 반환 값과 동일한 CPU 레지스터에 저장되기 때문입니다.
참고 : 한 의견에서 언급 한 바와 같이, 이것은 정의되지 않은 동작이며 모든 작업에서 작동하지 않을 수도 있습니다. 그리고 모든 컴파일러 최적화는 그냥 건너 뜁니다.
또 다른 유용한 기능 : X-Macros는 변수 목록이 있고 모든 변수를 포함하는 작업을 수행해야 할 때 도움이 될 수 있습니다.
-O0
항상 반환 값 레지스터의 표현식을 평가하도록 선택합니다. 적어도 x86, ARM 및 MIPS를 살펴 보았으며 ( gcc.godbolt.org ) gcc는에서 그렇게하지 않는 것 같습니다 -O0
. 당신이 활용하지만 기억 당신이 프로그래밍하는 언어 gcc -O0
, 하지 C를 하지 C로, 당신은 그에 따라 답을 레이블한다 . -O0
디버그 모드 이외의 최적화 수준에서는 실패하며 clang IIRC에서는 작동하지 않습니다.
배열의 첫 번째 요소에 액세스하는 *a
대신 사용하십시오 a[0]
.
관계 연산자 ( !=
, >
등)는 0
또는을 제공 1
합니다. 조건이 참인지 거짓인지에 따라 서로 다른 오프셋을 제공하는 산술 연산자로 이것을 사용하여 a[1+2*(i<3)]
액세스 할 a[1]
경우 i >= 3
와 a[3]
그렇지 않은 경우.
a[i<3?3:1]
보다 짧은 두 문자 a[1+2*(i<3)]
입니다.
IOCCC 자료실 (국제 난독 화 C 코드 경연 대회)을 살펴볼 수 있습니다.
주목할만한 트릭 중 하나는 확장에 불균형 괄호 / 괄호가있는 매크로를 #define하는 것입니다.
#define P printf(
#define P;printf(
.
for(int i=0;i<n;i++){a(i);b(i);}
몇 가지 방법으로 더 짧게 만들 수 있습니다.
for(int i=0;i<n;){a(i);b(i++);}
루프 ++
에서 마지막 i
으로
이동하기위한 -1
for(int i=0;i<n;b(i++))a(i);
하나의 문장을 제외한 모든 문장을 메인 루프의 상단 및 상단 루프로 이동하여 중괄호를 제거하면 -3 더
동일한 시그니처를 사용하고 단일 표현식으로 정의 된 간단한 함수로 문제를 줄일 수 있다면 #define r return
, 함수를 정의하기 위해 거의 모든 상용구 보다 더 잘 수행 할 수 있습니다 .
#define D(f,...)f(x){return __VA_ARGS__;}
D(f,x+2)
D(g,4*x-4)
D(main,g(4))
프로그램 결과는 OS 또는 제어 쉘 또는 IDE로 리턴되는 상태 값입니다.
사용은 __VA_ARGS__
당신이 다음에 순서 포인트를 소개하는 쉼표 연산자를 사용할 수 있도록 기능 표현식 . 이것이 필요하지 않으면 매크로가 더 짧아 질 수 있습니다.
#define D(f,b)f(x){return b;}
다음 대신에 문자를 인쇄 한 다음 캐리지 리턴을 인쇄하십시오.
printf("%c\n",c);
또는
putchar(c);putchar('\n'); // or its ascii value, whatever!
간단히, c를 int로 선언하고 :
puts(&c);
puts(&c)
정말 작동? 반드시 null로 끝나는 것은 아닙니다.
char *
문자 : 우리는 단일 문자열 참조 C , null 바이트 다음을.
를 사용 asprintf()
하면 명시 적으로 할당하고 문자열 길이를 측정 할 수 있습니다 char*
! 이것은 코드 골프에 너무 유용하지는 않지만 char 배열로 일상적인 작업을 용이하게합니다. 21 세기 C 에는 더 좋은 조언이 있습니다.
사용 예 :
#define _GNU_SOURCE
#include <stdio.h>
int main(int argc, char** argv) {
char* foo;
asprintf(&foo, "%s", argv[1]);
printf("%s",foo);
}
import
당신이해야한다면첫 번째 답변 에서 언급했듯이 일부 컴파일러 (특히 GCC 및 clang)를 사용하면 #include
표준 라이브러리 기능 을 생략 할 수 있습니다 .
를 제거 할 수 없더라도 피할#include
수있는 다른 방법 이있을 수 있지만 항상 실용적이거나 특히 골프는 아닙니다.
나머지 경우 에는 바이트를 저장하는 #import<header file>
대신 사용할 수 있습니다 #include<header file>
. 이것은 GNU 확장이며 더 이상 사용되지 않는 것으로 간주되지만 적어도 gcc 4.8, gcc 5.1 및 clang 3.7에서 작동합니다.
여기에 내가 사용했던 몇 가지 팁이 있습니다. 나는 타인에게 뻔뻔스럽게 도난 당 했으므로 나 외에는 누구에게도 신용하지 않습니다.
할당을 함수 호출과 결합
이 대신에 :
r = /* Some random expression */
printf("%d", r);
이 작업을 수행:
printf("%d", r = /* Some random expression */);
여러 변수를 함께 초기화 (가능한 경우)
이 대신에 :
for(i=0,j=0;...;...){ /* ... */ }
이 작업을 수행:
for(i=j=0;...;...){ /* ... */ }
0/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 */
R*-~!!mxxxx
기본적인 논리적 평등을 알면 몇 바이트를 절약 할 수 있습니다. 예를 들어, if (!(a&&b)){}
DeMorgan 's law 대신에 시도하십시오 if (!a||!b){}
. 비트 함수에도 동일하게 적용됩니다 . ~(a|b)
do 대신 ~a&~b
.