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