Ich verstehe diesen C/C++ Witz nicht

Lesezeit: 6 Minuten

Benutzer-Avatar
Butterblume

Nachdem ich das gelesen habe Artikel auf thedailywtf.com bin ich mir nicht sicher, ob ich den Witz wirklich verstanden habe.

Dort steht, dass irgendein Typ den Code geÀndert hat

int function() 
{ 
  int x;
  char data_string[15];
  ...
  x = 2;
  strcpy(data_string,"data data data");
  ...
}

zu

int function() 
{
  int x = 2;
  char data_string[15] = "data data data";
  ...
}

ĂŒberall im Code und das hat aus irgendeinem Grund die GrĂ¶ĂŸe der ausfĂŒhrbaren Datei von 1 auf 2 CDs erhöht (oder hat es das vielleicht nicht getan?).

Offensichtlich bin ich mit C/C++ nicht vertraut genug, um diesen Witz zu verstehen, aber was mir am seltsamsten erscheint, ist, dass das zweite Code-Listing “sauberer” erscheint – zumindest nach dem, was mir in der Schule gesagt wurde (das heißt, dass das Initialisieren von Variablen eine gut, nicht schlecht).

Benutzer-Avatar
DigitalRoss

OIC, dies ist ein Quellcode-Churn-Problem

Auf den ersten Blick sind die beiden Formen gleichwertig. Das zweite sieht schöner aus, aber sie tun dasselbe.

Aber dann las ich die zitierte Seite.

Das Problem ist, dass der Neue den Quellbaum aufgewĂŒhlt hat, jede Menge davon. Es ist kein guter Stil, durch einen riesigen Quellbaum zu trollen und eine bedeutungslose Änderung vorzunehmen. Sicher, vielleicht ist ein Stil etwas besser als der andere, aber in der Praxis sollte es so sein viel besser bevor 1.000 Deltas in ein Quellcode-Kontrollsystem gesteckt werden, damit die Leute sich ewig durchwĂŒhlen können, ist gerechtfertigt.

Ich vermute, dass dies der Fall war eine Quellenfreigabe, oder eine andere nicht erwĂ€hnte KomplexitĂ€t fĂŒhrte dazu, dass die Bearbeitung so vieler Dateien ihre Verbreitung ausweitete. Die BeitrĂ€ge zu dieser Seite sind ziemlich redigiert, aber im Grunde ist das Problem ohne Einzelheiten verstĂ€ndlich.

Eines der Probleme bei der Bearbeitung von zig Millionen Dateien fĂŒr eine StilĂ€nderung besteht darin, dass die Wahrscheinlichkeit eines versehentlichen Fehlers steigt. Diese Chance wird stark vervielfacht, wenn ein Junior-Entwickler dies tut. Auch fĂŒr Erfahrene gibt es Murphys Gesetz zu beachten. Wenn es kurz vor einer Veröffentlichung passiert, ist es wirklich ein hĂ€ngendes Vergehen.

  • Ich stimme zu. Sie erwĂ€hnten Quellcode-Churning. Obwohl ich noch nie in einem solchen GeschĂ€ft gearbeitet habe, habe ich GerĂŒchte ĂŒber Unternehmen gehört, die die ProduktivitĂ€t anhand von Metriken messen, z. B. wie viele Dateien in das Quellcodeverwaltungssystem eingecheckt werden. Wenn diese Person in einem solchen GeschĂ€ft arbeitete (und ich gehe nicht davon aus, dass dies der Fall war), könnte sie viel Anerkennung fĂŒr minimale Arbeit erhalten.

    – Anthony Gatlin

    14. September 2009 um 8:02 Uhr

Je nach Compiler und Compileroptionen erfolgt die Initialisierung wie folgt

char data_string[15] = "data data data";

fĂŒhrt zu vielen Bewegungsanweisungen, um die wörtlichen Daten auf den Stapel zu kopieren.

Berufung strcpy erfordert weniger Anweisungen.

Wenn Sie so etwas ĂŒber eine große Codebasis machen, kann dies die BinĂ€rgrĂ¶ĂŸe erheblich erhöhen.

Und natĂŒrlich verbrachte er seine Zeit nicht damit, Mehrwert zu schaffen.

  • @DigitalRoss: Ja, das verstehe ich und habe es nicht hervorgehoben, da es bereits von anderen Antworten abgedeckt wurde. Ich habe mich auf das Problem der CodegrĂ¶ĂŸe konzentriert. Die Untersuchung der Assemblyausgabe verschiedener Compiler zeigt, dass es erhebliche Unterschiede in der CodegrĂ¶ĂŸe zwischen den beiden Init-Stilen geben kann.

    – laalto

    14. September 2009 um 9:02 Uhr

  • @laalto: Wie Sie meinem eigenen Beitrag entnehmen können, konnte ich dieses Ergebnis nicht reproduzieren. Welche Compiler zeigten einen Unterschied?

    – SingleNegationElimination

    14. September 2009 um 16:38 Uhr

  • @TokenMacGuy: Zum Beispiel i686-apple-darwin8-gcc-4.0.1

    – laalto

    15. September 2009 um 12:56 Uhr

  • @reptrich: Das ist eine Möglichkeit, aber beide können beides tun. Beispielsweise ersetzt eine gĂ€ngige MSVC++-Optimierung Aufrufe bestimmter Bibliotheksfunktionen wie strcpy() und memcpy() mit inlinierten “Intrinsics”; und der Compiler kann eine interne Bibliotheksfunktion aufrufen, um die In-Place-Array-Initialisierung durchzufĂŒhren.

    – j_random_hacker

    6. April 2010 um 3:57 Uhr

  • Diese Antwort ist nicht richtig. Der Punkt des “Witzes” ist, dass diese Art von Änderung sinnlos ist.

    – nibot

    28. Juni 2013 um 16:46 Uhr

2. Code ist in der Tat “sauberer”, aber bei einem Projekt der GrĂ¶ĂŸe, um die es in diesem Artikel geht, ist es lĂ€cherlich zu glauben, dass ein solches Refactoring bestenfalls nutzlos und im schlimmsten Fall fehleranfĂ€llig ist.

Diese Art der Umgestaltung blĂ€st jedoch keine .Exe-GrĂ¶ĂŸe von 1 bis 2 CDs auf

Ich kann daraus kein unterschiedliches Verhalten ableiten. Ich habe es mit probiert LLVM: Ich musste beim RĂŒckgabewert nur ein bisschen Cruft hinzufĂŒgen, damit LLVM nichts wegoptimiert, sondern den generierten Code fĂŒr wtf und wtf2 sind völlig identisch. Dieses wtf ist BAAAAAD

Eingang

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int wtf(int X) {
  int x;
  char data_string[15];
  x = 2;
  strcpy(data_string,"data data data");
  return 5*X+x+ data_string[X];
}
int wtf2(int X) {
  int x = 2;
  char data_string[15]="data data data";
  return 5*X+x+ data_string[X];
}
int main(int argc, char **argv) {
  printf("%d\n", wtf(atoi(argv[1]))+wtf2(atoi(argv[1])));
}

Ausgabe:

; ModuleID = '/tmp/webcompile/_3856_0.bc'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-pc-linux-gnu"
@.str = internal constant [15 x i8] c"data data data\00"        ; <[15 x i8]*> [#uses=3]
@.str1 = internal constant [4 x i8] c"%d\0A\00"     ; <[4 x i8]*> [#uses=1]

define i32 @wtf(i32 %X) nounwind readnone {
entry:
    %0 = mul i32 %X, 5      ; <i32> [#uses=1]
    %1 = getelementptr [15 x i8]* @.str, i32 0, i32 %X      ; <i8*> [#uses=1]
    %2 = load i8* %1, align 1       ; <i8> [#uses=1]
    %3 = sext i8 %2 to i32      ; <i32> [#uses=1]
    %4 = add i32 %0, 2      ; <i32> [#uses=1]
    %5 = add i32 %4, %3     ; <i32> [#uses=1]
    ret i32 %5
}

define i32 @wtf2(i32 %X) nounwind readnone {
entry:
    %0 = mul i32 %X, 5      ; <i32> [#uses=1]
    %1 = getelementptr [15 x i8]* @.str, i32 0, i32 %X      ; <i8*> [#uses=1]
    %2 = load i8* %1, align 1       ; <i8> [#uses=1]
    %3 = sext i8 %2 to i32      ; <i32> [#uses=1]
    %4 = add i32 %0, 2      ; <i32> [#uses=1]
    %5 = add i32 %4, %3     ; <i32> [#uses=1]
    ret i32 %5
}

define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
    %0 = getelementptr i8** %argv, i32 1        ; <i8**> [#uses=1]
    %1 = load i8** %0, align 4      ; <i8*> [#uses=1]
    %2 = tail call i32 @atoi(i8* %1) nounwind readonly      ; <i32> [#uses=2]
    %3 = getelementptr [15 x i8]* @.str, i32 0, i32 %2      ; <i8*> [#uses=1]
    %4 = load i8* %3, align 1       ; <i8> [#uses=1]
    %5 = sext i8 %4 to i32      ; <i32> [#uses=1]
    %tmp2 = mul i32 %2, 10      ; <i32> [#uses=1]
    %6 = shl i32 %5, 1      ; <i32> [#uses=1]
    %7 = add i32 %6, 4      ; <i32> [#uses=1]
    %8 = add i32 %7, %tmp2      ; <i32> [#uses=1]
    %9 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr ([4 x i8]* @.str1, i32 0, i32 0), i32 %8) nounwind     ; <i32> [#uses=0]
    ret i32 undef
}

declare i32 @atoi(i8*) nounwind readonly

declare i32 @printf(i8*, ...) nounwind

Ähm, lies den Artikel noch einmal 🙂

Das wirkliche WTF war, dass er die gesamte Lösung mit dieser Art von Änderungen berĂŒhrte, als er ein Speicherleck beheben sollte.

Auch eine Änderung wie diese wĂŒrde nicht viel ausmachen, außer dass möglicherweise Fehler in anderen, möglicherweise komplizierteren Dateien als der Beispieldatei behoben/eingefĂŒhrt werden.

Benutzer-Avatar
scharfer Zahn

Ja, der zweite Code ist sauberer, kann aber je nach Compiler dazu fĂŒhren, dass mehr Maschinencode ausgegeben wird. Dies ist vollstĂ€ndig vom Compiler abhĂ€ngig, aber der Punkt des WTF-Artikels ist, dass der Compiler im zweiten Fall eine Kopie des String-/Ganzzahlwerts fĂŒr jedes Code-Snippet so zuweisen wĂŒrde und im ersten Fall nur einmal pro Programm .

1385700cookie-checkIch verstehe diesen C/C++ Witz nicht

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy