Twoje zadanie jest proste. Napisz program, który oczywiście powinien generować błąd na pierwszy rzut oka, zarówno podczas kompilacji, jak i uruchamiania, ale albo nie, albo generuje jakiś inny niepowiązany błąd. To konkurs popularności, więc bądź kreatywny.
Chciałbym móc go znaleźć ... był stary przykład PL / I, który zawierał zdanie w stylu „jeśli jeśli jeśli = to wtedy, to wtedy = inaczej else = jeśli wtedy jeszcze ...” (PL / I zezwolił na użycie jego słowa kluczowe jako nazwy zmiennych, i miał wyrażenie warunkowe podobne do C ?, które również używało słów kluczowych if / then / else ...)
Upewnij się, że skompilowałeś następujący kod w standardowym trybie zgodnym (na przykład dla g ++ użyj flagi -ansi):
int main()
{
// why doesn't the following line give a type mismatch error??/
return "success!";
}
Jak to działa:
?? / jest sekwencją trygraficzną, która jest tłumaczona na odwrotny ukośnik, który ucieka przed następną nową linią, więc następny wiersz jest nadal częścią komentarza i dlatego nie wygeneruje błędu składniowego. Zauważ, że w C ++ pominięcie powrotu mainjest dobrze zdefiniowane i równoznaczne ze zwróceniem 0, co oznacza pomyślne uruchomienie.
Oto bardziej przyziemny, który już wcześniej mnie dopadł:
x = 42
if x < 0
raise Exception, "no negatives please"
elseif x == 42
raise Exception, "ah! the meaning of life"
else
p 'nothing to see here...'
end
Drukuje „nic do zobaczenia”.
To elsif nie elseif . (i na pewno nie jest elif - biada niepoprawnemu programistowi pythonowemu (mnie)!) Więc interpreter elseif wygląda jak normalne wywołanie metody, a ponieważ nie wchodzimy do bloku x <0, przechodzimy od razu do innego i nie zgłaszaj wyjątku. Ten błąd jest niezwykle oczywisty w każdym środowisku wyróżniającym składnię, na szczęście (?) Kod golfowy nie jest takim środowiskiem.
To Haskell, a nie C. Definiuje funkcję o nazwie „void”, która przyjmuje dwa argumenty. Pierwszy nosi nazwę „main”, a jeśli drugi (nienazwany) jest pustą krotką, zwraca zmienną „main”. „-” rozpoczyna komentarz w Haskell, więc „;” jest skomentowany.
Nazwałbym to oszustwem, a nie kreatywnością. Musisz zdefiniować środowisko, w którym działasz, zanim będziesz w stanie zastanowić się, czy jakiś kod będzie zawierał błąd, czy nie. W przeciwnym razie mógłbym dać ci szum linii, który jest Malbolge i zapytać, czy się kompiluje.
zbyt oczywiste dla każdego, kto wcześniej tego doświadczył. Jestem pewien, że wpadnie na to wielu początkujących i tak zwanych „ekspertów internetowych”.
Oczywisty? Więc zawsze patrzysz na swoje nazwy zmiennych za pomocą ich numerów Unicode zamiast ich wyglądu? Możesz to zauważyć, jeśli wyszukujesz „a” (lub „a”?) I nie możesz znaleźć tego, czego oczekujesz, ale po prostu czytając, nie możesz tego zobaczyć (przynajmniej w pokazanej tu czcionce).
Jak zapewne wiesz, w JavaScript wszystko oprócz literałów jest przedmiotem. Liczby są również obiektami. Tak więc teoretycznie (i praktycznie) możesz uzyskać właściwości lub metody wywoływania dowolnych literałów za pomocą notacji kropkowej, tak jak ty 'string'.lengthlub [1,2,3].pop(). W przypadku liczb możesz zrobić to samo, ale należy pamiętać, że po pojedynczej kropce analizator będzie szukał ułamkowej części liczby oczekującej wartości zmiennoprzecinkowej (jak w 123.45). W przypadku korzystania z całkowitą należy „powiedzieć” parser że część ułamkowa jest pusty, wyznaczając dodatkowy kropkę przed zajęcie nieruchomości: 123..method().
Źle się czujesz, będąc doskonale przyzwyczajonym do ..notacji, ale całkowicie nieświadomy w odniesieniu do .toString(a freaking argument here?)notacji: P No cóż, już się zorientowałem :)
#!/bin/bash[1<2]&& exit
for i in`seq 1 $[2 ** 64]`do"$0"|"$0"donewhile[[ false ]]do:doneif maybe
do[:[:[:[:[;[;[;[;;];];];]:]:]:]:]fi
Wyniki
Można się spodziewać, że skrypt nie generuje żadnych błędów, ponieważ kończy działanie po pierwszym poleceniu. Nie ma
Można się spodziewać typowych komunikatów o błędach spowodowanych trwającą bombą widełkową z powodu forpętli. Nie ma bomby widelcowej.
Możesz spodziewać się, że bash narzeka na brakujące maybepolecenie lub całą masę błędów składniowych w ifbloku. Nie będzie.
Jedyny komunikat o błędzie, który może wygenerować skrypt, kończy się 2: No such file or directory.
Wyjaśnienie
[nie jest specjalny do bash, więc < 2wykonuje, jak zwykle, przekierowanie. Jeśli 2w bieżącym katalogu nie ma pliku o nazwie , spowoduje to błąd.
Z powodu powyższego błędu powyższe polecenie &&będzie miało niezerowy status wyjścia i exitnie zostanie wykonane.
forPętli nie jest nieskończona. W rzeczywistości nie ma w ogóle pętli. Ponieważ bash nie może obliczyć 64 potęgi 2, wynikiem wyrażenia arytmetycznego jest 0.
[[ false ]]sprawdza, czy falsejest łańcuchem zerowym. Tak nie jest, więc ta whilepętla jest nieskończona.
Z tego powodu ifinstrukcja nigdy nie zostanie wykonana, więc nie zostaną wykryte żadne błędy.
class Gotcha {
public static void main(String... args) {
try {
main();
} finally {
main();
}
}
}
Tutaj nie ma przepełnienia stosu; poruszać się.
Na pierwszy rzut oka powinno to dać StackOverflowError, ale tak nie jest! W rzeczywistości po prostu działa wiecznie (przynajmniej do wszystkich praktycznych celów; technicznie zakończyłby się po pewnym czasie o wiele rzędów wielkości dłużej niż wiek wszechświata). Jeśli chcesz wiedzieć, jak / dlaczego to działa, zobacz to . Ponadto, jeśli zastanawiasz się, dlaczego możemy wywoływać main()bez argumentów, gdy główna metoda generalnie potrzebuje String[]argumentu, to dlatego, że zadeklarowaliśmy go tutaj jako argument zmienny, co jest całkowicie poprawne.
Mówisz „Tutaj nie ma przepełnienia stosu”, kiedy w rzeczywistości system ciągle przepuszcza przepełnienie stosu i ostatecznie wygeneruje wyjątek przepełnienia stosu. (jak wspomniałeś, ostatecznie może to potrwać bardzo długo) I zależy to od głębokości stosu. Na mniejszej maszynie wirtualnej lub systemie osadzonym głębokość stosu może być znacznie mniejsza.
@McKay To stwierdzenie jest wyraźnie zwykłą, niepotrzebną linią, której nie należy traktować dosłownie. OP prosi o program, który wygląda jak powinien powodować błąd, ale nie robi tego. W ogólnym przypadku powyższa odpowiedź spełnia ten wymóg. Jasne, możemy wymyślić niejasną sytuację, w której tak nie jest, ale to nie unieważnia odpowiedzi. Mam nadzieję, że ponownie rozpatrzysz swoją opinię.
@McKay Nawiasem mówiąc, załóżmy, że rozmiar stosu jest niewielki (np. 100 w przeciwieństwie do normalnego ~ 10 000) i nadal możemy wykonywać 10 000 000 połączeń na sekundę. Następnie całkowity czas pracy wynosi 4 019 693 684,133,147 lat - wciąż wiele rzędów wielkości większych niż wiek wszechświata.
What? No error? Yep, this code does not have any bugs, why would it?
?po nim spacja to operator, który wywołuje funkcję, ale tylko jeśli istnieje. JavaScript nie ma wywoływanej funkcji What, dlatego funkcja nie jest wywoływana, a jej argumenty są po prostu ignorowane. Inne słowa w kodzie to wywołania funkcji, które w rzeczywistości nie są wywoływane, ponieważ Whatfunkcja nie istnieje. Na koniec ?jest operatorem istnienia, ponieważ nie jest używany w funkcji wywołania. Inne zakończenia zdań, takie jak .lub !nie działałyby tak jak w .przypadku metod, i !nie są operatorem (którego nie można użyć po identyfikatorze). Aby dowiedzieć się, jak CoffeeScript przekonwertował to na JavaScript, odwiedź http://coffeescript.org/#try:What%3F%20No%20error%3F%20Yep%2C%20this%20code%20does%20not%20have%20any%20bugs%2C % 20 dlaczego% 20it% 20 chciałbym% 3F .
&Operator w VBScript jest ciąg konkatenacji, ale to, co na ziemi są &&i &&&operatorów? (Pamiętaj, że operator „i” w VBScript Andnie jest &&.)
x = 10&987&&654&&&321
Ten fragment programu jest legalnym VBScript. Dlaczego? Jaka jest wartość x?
Lexer rozbija to jako x = 10 & 987 & &654& & &321. Literał całkowity, który zaczyna się od, &jest, co dziwne, literałem ósemkowym. Oktalowy literał, który kończy się, &jest, co bardziej dziwne, długą liczbą całkowitą. Więc wartość x jest połączeniem wartości dziesiętnych tych czterech liczb: 10987428209.
Na dowolnej platformie (w tym współczesnej x86), w której strony mogą być odczytywane bez możliwości wykonywania, spowoduje to awarię po wejściu na, mainponieważ mainzostało umieszczone w segmencie danych, który nie jest wykonywalny. Zabawnie, const int main=195będzie nie upaść (na x86) (ale będzie produkować śmieci status wyjścia), ponieważ .rodatadomyślnie jest umieszczany w tym samym segmencie, .texta zatem jest wykonywalny. ( const char main[]="1\300\303";zakończy się sukcesem! (wciąż na x86))
public static void main(String[] varargs) throws Exception{
char a, b = (char)Integer.parseInt("000d",16);
// Chars have \u000d as value, so they're equal
if(a == b){
throw new Exception("This should be thrown");
}
}
Co?
Zgłasza błąd składni po \u000d. \u000djest Unicode dla nowej linii. Mimo że jest komentowany, kompilator Java traktuje to, co po nim, jako kod, ponieważ nie jest już komentowany.
Pytanie brzmiało: „kod, który wygląda, jakby zawiódł, ale nie”, a nie „kod, który wygląda, że zawodzi, ale robi to w inny sposób”. Błąd składniowy zamiast wyjątku jest nadal błędem.
#include <iostream>
int succ(int x)
{
return x + 1;
}
int succ(double x)
{
return int(x + 1.0);
}
int succ(int *p)
{
return *p + 1;
}
int main()
{
std::cout << succ(NULL) << '\n';
}
Dlaczego?
NULLjest stałą międzygalową, więc odpowiada intprzeciążeniu ściśle lepiej niż ta int*. Mimo to większość programistów ma NULLpowiązania ze wskaźnikami, więc można się spodziewać zerowego odchylenia wskaźnika.
Na szczęście C ++ 11 pozwala implementacjom zdefiniować NULLjako nullptr, a implementacje, które to robią (jeszcze nie wiem, ale ich oczekuję) spowodują oczekiwany błąd segmentacji.
Idealnie poprawny, ale wynik jest trudny do odgadnięcia. Pierwsze 3 "znaki rozpoczynają ciąg wielowierszowy, a następne dwa są częścią ciągu. Na końcu pierwsze trzy" kończą ciąg, a ostatnie dwa są literałami pustych ciągów, które są parowane przez analizator składni z ciągiem wielowierszowym .
IEEE 754 określa dwa modele: sygnalizowanie NaN / Inf (które podnoszą wyjątki w podziale zera FP, pierwiastek kwadratowy z -1, niedopełnienie / przepełnienie itp.) Oraz brak sygnalizacji (który traktuje NaN/ Infpodobnie jak zwykłe wartości argebraiczne z dobrze zdefiniowaną matematyką na nich). Nowoczesny sprzęt FP można skonfigurować do pracy w obie strony. Niezależne od języka; wstyd nie wiedzieć.
Mieszanie trygrafów i lambda bez przestrzeni może być dość mylące i zdecydowanie wyglądać błędnie dla osób, które nie są świadome trygrafów:
int main()
{
return??-??(??)()??<return"??/x00FF";??>()??(0??);
}
Jak to działa:
Niektóre sekwencje składające się z 3 symboli, zaczynające się od ??, nazywane są trigrafami i zostaną zastąpione przez w pełni zgodny preprocesor. Wstępnie przetworzona linia, o której mowa, wygląda następująco: return ~ [] () {return "\ x00FF"; } () [0]; Jak widać, jest to tylko zbędna funkcja lambda zwracająca ciąg znaków składający się ze znaku 0xFFth. [0] właśnie wydobywa tę postać i ~ niezapominajki, więc 0 jest zwracana.
@Joe Z [](){}jest funkcją lambda, podobnie jak [](int a){return a+1;}jedna. ([](){})()wywołuje tę funkcję, zwracając, voidjeśli się nie mylę. Całość (([](){})());sprowadza się więc do (void);, co jest stwierdzeniem, że nic nie robi. mainwtedy po prostu zwraca zero, tak jak powinno bez returninstrukcji.
Private Sub DivByZero()
Dim x() As String
x = Split(vbNullString, ",")
Debug.Print 1 / UBound(x)
End Sub
Rozdzielenie pustego łańcucha rozdzielanego przecinkami powinno dać pustą tablicę. Czy powinien być oczywisty podział przez zero błędów, prawda?
Nie. Zaskakujące jest, że gdy dowolny ciąg o zerowej długości jest dzielony, środowisko wykonawcze daje tablicę z dolną granicą 0 i górną granicą -1. Powyższy kod wyświetli -1.
@minitech Yep. Rozumiem, że to był błąd w oryginalnej implementacji Split w VB6. W .NET celowo „dodali” (a może udokumentowano to lepsze słowo) zachowanie pustych tablic zwracających UBound równe -1 w celu zachowania kompatybilności wstecznej z całym kodem VB6, który skorzystał z tego hacka. Dzielenie łańcucha zerowego jest jedynym sposobem na natywne uzyskanie tej tablicy w VBA / VB6 bez wywołań interfejsu API systemu Windows.
Więc sztuczka polega na tym, że nie wykona bloku PHP, ponieważ plik ma .htmlrozszerzenie, a twój serwer internetowy nie jest skonfigurowany do analizowania .htmlplików jako PHP?
? Okazuje się, że jest to legalne w VBScript, ale nie w VB6. Dlaczego?
To błąd w parserze; celem było odrzucenie tego. Kod, który wykrywa, End Ifmiał także sprawdzić, czy była to Ifinstrukcja wieloliniowa , a nie zrobił tego. Kiedy próbowałem to naprawić i wysłałem wersję beta z poprawką, pewna wpływowa organizacja branżowa odkryła, że ma ten wiersz kodu w jednym ze swoich programów VBScript i powiedziała, że przyznają nowej wersji niską ocenę, chyba że usuniemy naprawiono błąd, ponieważ nie chcieli zmieniać kodu źródłowego.
Przypomniało mi to błąd, który napotkałem, gdy nauczyłem się C. Niestety, oryginalny wariant nie działa z obecnym GCC, ale ten nadal:
#define ARR_SIZE 1234
int main() {
int i = ARR_SIZE;
int arr[ARR_SIZE];
while(i >= 0) {
(--i)[arr] = 0;
}
i = *(int*)0;
}
To oczywiście segreguje, ponieważ nie uwzględniamy wskaźnika zerowego, prawda?
Źle - w rzeczywistości jest to nieskończona pętla, ponieważ nasz stan pętli jest wyłączony o jeden. Z powodu zmniejszenia przedrostka idziała od 1023 do -1. Oznacza to, że przypisanie zastępuje nie tylko wszystkie elementy arr, ale także lokalizację pamięci bezpośrednio przed nią - która przypadkiem jest miejscem iprzechowywania. Po osiągnięciu -1, inadpisuje się z 0a więc warunek jest spełniony pętla ponownie ...
To był oryginalny wariant I, którego nie mogę już odtworzyć:
To samo działało z iprzejściem w górę od 0 i wyłączeniem jednego. Najnowszy GCC zawsze zapisuje iwcześniej arrw pamięci; musiało być inaczej w starszych wersjach (być może w zależności od kolejności deklaracji). To był prawdziwy błąd, który popełniłem w jednym z moich pierwszych programów zabawek dotyczących tablic.
Jest to również oczywiste, jeśli wiesz, jak działają wskaźniki w C, ale może być zaskakujące, jeśli nie:
Możesz pomyśleć, że przypisanie do (--i)[arr]powoduje błąd, ale jest prawidłowe i równoważne z arr[--i]. Wyrażenie a[x]jest po prostu cukrem składniowym, dla *(a + x)którego oblicza i odsyła wskaźnik do indeksowanego elementu; dodanie jest oczywiście przemienne, a zatem równoważne z *(x + a).
public class WhatTheHeckException extends RuntimeException {
private static double d; // Uninitialized variable
public static void main(String... args) {
if (d/d==d/d) throw new WhatTheHeckException();
// Well that should always be true right? == is reflexive!
System.out.println("Nothing to see here...");
}
}
Dlaczego to działa:
Jednostkowe pola mają wartości domyślne. W tym przypadku d wynosi tylko 0 . 0/0 = NaN w podwójnym dzieleniu, a NaN nigdy się nie równa, więc if zwraca false. Zauważ, że to nie zadziałałoby, gdybyś miał 0/0 == 0/0 , ponieważ w przy całkowitym podziale 0/0 Mógłby wygenerować wyjątek ArithmeticException .
Kompiluje i uruchamia się bez żadnych ostrzeżeń z g++ -pedantic-errors -std=c++11.
compljest standardową alternatywną pisownią dla ~, tak jak notjest alternatywą dla !. complsłuży tutaj do nadpisania, operator~a następnie zdefiniowania destruktora. Inną sztuczką jest to, że operator compjest to funkcja konwersji z typu compna samą. Co zaskakujące, standard nie zabrania takiej funkcji konwersji - ale mówi, że taka funkcja nigdy nie jest używana.
function[:(](["):"]):[:(]=["):"]:
end function
msgbox getref(":(")(":)")
'Output: :)
Co to robi:
Nazwy funkcji, sub i zmiennych w VBScript mogą być dowolne, jeśli używasz nawiasów kwadratowych. Ten skrypt tworzy wywoływaną funkcję :(i jeden argument, "):"ale ponieważ nie przestrzegają normalnej konwencji nazewnictwa, są otoczone nawiasami kwadratowymi. Wartość zwracana jest ustawiona na wartość parametru. Dodatkowy dwukropek służy do uzyskania wszystkiego w jednej linii. Instrukcja Msgbox pobiera odwołanie do funkcji (ale nie potrzebuje nawiasów) i wywołuje ją z uśmieszkiem :)jako parametrem.
Właściwie złapałem się na tym, że mylnie to robię :)
public static object Crash(int i)
{
if (i > 0)
return i + 1;
else
return new ArgumentOutOfRangeException("i");
}
public static void Main()
{
Crash(-1);
}
enum derp
{
public static void main(String[] a)
{
System.out.println(new org.yaml.snakeyaml.Yaml().dump(new java.awt.Point()));
}
}
I jak to działa:
Podejrzewasz, że uważasz, że Enum jest nieważne, ale jest ważne; wtedy myślisz, że wypisze standardowe atrybuty obiektów Point, ale Gotcha! ze względu na sposób serializacji Snakeyaml otrzymujesz płynny błąd StackOverFLow
I kolejny:
enum derp
{
;public static void main(String[] a)
{
main(a);
}
static int x = 1;
static
{
System.exit(x);
}
}
myślisz, że wystąpi przepełnienie stosu z powodu oczywistej rekurencji, ale program nadużywa faktu, że kiedy go uruchomisz, static{} blockzostanie on wykonany jako pierwszy i dlatego kończy działanie przed ładowaniem main ()
enum derp
{
;
public static void main(
String[] a)
{
int aa=1;
int ab=0x000d;
//setting integer ab to \u000d /*)
ab=0;
/*Error!*/
aa/=ab;
}
static int x = 1;
}
ten opiera się na tym /*Error*/-komentowanym kodzie jako punkcie końcowym komentarza otwartego przed ab = 0; wyjaśnienie liczby całkowitej ab do 0x000d ukrywa nowy wiersz, aby aktywować komentarz do następnego wiersza
Chciałem tylko przypomnieć ludziom o ważnej, ale niekonwencjonalnej notacji - zrób to, co chcesz. Z pewnością rozejrzałbym się trzy razy, zanim powiem, że to jest ważne. Po pierwsze, wyrażenia takie jak 5 [ciąg] nie są dobrze znane zwykłemu koderowi i są sprzeczne z logiką indeksowania tablic. Po drugie, ciąg „” + wygląda jak dodanie 2 ciągów, ale z niewłaściwym typem cudzysłowu. Po trzecie, i i ++ wygląda jak adres liczby całkowitej (ale pierwszeństwo to załatwia). Wreszcie, piszemy poza literałem ciągów (ale nie poza większym buforem kopii zapasowej).
Używamy plików cookie i innych technologii śledzenia w celu poprawy komfortu przeglądania naszej witryny, aby wyświetlać spersonalizowane treści i ukierunkowane reklamy, analizować ruch w naszej witrynie, i zrozumieć, skąd pochodzą nasi goście.
Kontynuując, wyrażasz zgodę na korzystanie z plików cookie i innych technologii śledzenia oraz potwierdzasz, że masz co najmniej 16 lat lub zgodę rodzica lub opiekuna.