Warum erlaubt C keine Verkettung von Zeichenfolgen, wenn der Bedingungsoperator verwendet wird?

Lesezeit: 9 Minuten

Benutzeravatar von José D
Jos D.

Der folgende Code lässt sich ohne Probleme kompilieren:

int main() {
    printf("Hi" "Bye");
}

Dies kompiliert jedoch nicht:

int main() {
    int test = 0;
    printf("Hi" (test ? "Bye" : "Goodbye"));
}

Was ist der Grund dafür?

  • Die String-Verkettung ist Teil der frühen Lexing-Phase; es ist nicht Teil der Ausdruckssynatx von C. Mit anderen Worten, es gibt keine Wert vom Typ “String-Literal”. String-Literale sind vielmehr lexikalische Elemente des Quellcodes, die Werte bilden.

    – Kerrek SB

    16. Mai 2016 um 17:12 Uhr


  • Nur um die Antwort von @KerrekSB zu verdeutlichen: Die Verkettung der Zeichenfolgen ist Teil der Vorverarbeitung des Codetexts frühere es zusammenstellen. Während der ternäre Operator in der Laufzeit ausgewertet wird, nachdem der Code kompiliert wurde (oder falls alles konstant ist, kann dies in der Kompilierzeit erfolgen).

    – Eugen Sch.

    16. Mai 2016 um 17:15 Uhr


  • Detail: In diesem Beitrag "Hi" und "Bye" sind Zeichenfolgenliteralenicht Saiten wie in der C-Standardbibliothek verwendet. Mit Zeichenfolgenliteralewird der Compiler verketten "H\0i" "B\0ye". Nicht das gleiche mit sprintf(buf,"%s%s", "H\0i" "B\0ye");

    – chux – Wiedereinsetzung von Monica

    16. Mai 2016 um 19:18 Uhr


  • Mehr oder weniger der gleiche Grund, warum Sie es nicht tun können a (some_condition ? + : - ) b

    – Benutzer253751

    17. Mai 2016 um 10:15 Uhr


  • Beachten Sie das sogar printf("Hi" ("Bye")); funktioniert nicht – es erfordert keinen ternären Operator; die Klammer reicht (obwohl printf("Hi" test ? "Bye" : "Goodbye") würde auch nicht kompilieren). Es gibt nur eine begrenzte Anzahl von Token, die einem Zeichenfolgenliteral folgen können. Komma ,offene eckige Klammer [, close square bracket ] (wie in 1["abc"] – und ja, es ist grausam), runde Klammer schließen )geschweifte Klammer schließen } (in einem Initialisierer oder ähnlichen Kontext) und Semikolon ; sind legitim (und ein weiteres String-Literal); Ich bin mir nicht sicher, ob es noch andere gibt.

    – Jonathan Leffler

    17. Mai 2016 um 19:43 Uhr


Benutzeravatar von Sourav Ghosh
Sourav Ghosh

Gemäß C11-Standard, Kapitel §5.1.1.2, Verkettung benachbarter Zeichenfolgenliterale:

Benachbarte String-Literal-Tokens werden verkettet.

passiert in Übersetzungsphase. Auf der anderen Seite:

printf("Hi" (test ? "Bye" : "Goodbye"));

beinhaltet den Bedingungsoperator, der bei ausgewertet wird Laufzeit. Zur Kompilierzeit, während der Übersetzungsphase, sind also keine benachbarten Zeichenfolgenliterale vorhanden, daher ist die Verkettung nicht möglich. Die Syntax ist ungültig und wird daher von Ihrem Compiler gemeldet.


Um das etwas näher zu erläutern warum Während der Vorverarbeitungsphase werden die benachbarten Zeichenfolgenliterale verkettet und als einzelne dargestellt String-Literal (Zeichen). Der Speicher wird entsprechend zugewiesen und das verkettete String-Literal wird als a betrachtet einzelne Einheit (ein Zeichenfolgenliteral).

Andererseits sollte das Ziel im Falle einer Verkettung zur Laufzeit über genügend Speicher verfügen, um die Verkettung aufzunehmen String-Literal Andernfalls wird es keine Möglichkeit geben, dass die erwartet auf die verkettete Ausgabe kann zugegriffen werden. Nun, falls Zeichenfolgenliteralewird ihnen bereits zur Kompilierzeit Speicher zugewiesen und kann dies nicht sein erweitert um in jeden weiteren eingehenden Eingang zu passen hinein oder angehängt der ursprüngliche Inhalt. Mit anderen Worten, es gibt keine Möglichkeit, dass auf das verkettete Ergebnis als einzelnes zugegriffen (dargestellt) werden kann String-Literal. Dieses Konstrukt ist also von Natur aus falsch.

Nur zur Info, zur Laufzeit Schnur (nicht wörtlich) Verkettung haben wir die Bibliotheksfunktion strcat() die zwei verkettet Saiten. Achtung, die Beschreibung erwähnt:

char *strcat(char * restrict s1,const char * restrict s2);

Das strcat() Die Funktion hängt eine Kopie der Zeichenfolge an, auf die gezeigt wird s2 (einschließlich des abschließenden Nullzeichens) bis zum Ende von Zeichenfolge, auf die gezeigt wird s1. Das Anfangszeichen von s2 überschreibt das Nullzeichen am Ende von s1. […]

Also, wir können sehen, die s1 ist ein Schnurkein String-Literal. Als Inhalt jedoch s2 in keiner Weise verändert wird, kann es sehr wohl eine sein String-Literal.

  • Vielleicht möchten Sie eine zusätzliche Erklärung hinzufügen strcat: Das Zielarray muss lang genug sein, um die Zeichen zu empfangen s2 plus ein Null-Terminator nach den dort bereits vorhandenen Zeichen.

    – chqrlie

    30. April 2019 um 20:00 Uhr

Vlad aus Moskaus Benutzer-Avatar
Vlad aus Moskau

Nach C-Standard (5.1.1.2 Übersetzungsphasen)

1 Der Vorrang unter den Syntaxregeln der Übersetzung wird durch die folgenden Phasen festgelegt.6)

  1. Benachbarte String-Literal-Tokens werden verkettet.

Und erst danach

  1. Leerzeichen, die Token trennen, spielen keine Rolle mehr. Jedes Vorverarbeitungstoken wird in ein Token umgewandelt. Die resultierenden Token werden syntaktisch und semantisch analysiert und als Übersetzungseinheit übersetzt.

Bei dieser Konstruktion

"Hi" (test ? "Bye" : "Goodbye")

Es gibt keine angrenzenden Zeichenfolgenliteral-Token. Diese Konstruktion ist also ungültig.

  • Dies wiederholt nur die Behauptung, dass es in C nicht erlaubt ist. Es erklärt nicht warum, das war die Frage. Ich weiß nicht, warum es in 5 Stunden 26 Upvotes gesammelt hat … und die Akzeptanz nicht weniger! Herzliche Glückwünsche.

    – Leichtigkeitsrennen im Orbit

    16. Mai 2016 um 23:03 Uhr


  • Muss @LightnessRacesinOrbit hier zustimmen. Warum nicht (test ? "Bye" : "Goodbye") im Wesentlichen zu einem der Zeichenfolgenliterale auswerten Herstellung "Hi" "Bye" oder "Hi Goodbye"? (meine Frage wird in den anderen Antworten beantwortet)

    – Wahnsinnig

    17. Mai 2016 um 0:30 Uhr


  • @LightnessRacesinOrbit, denn wenn Leute normalerweise fragen, warum etwas nicht in C kompiliert wird, fragen sie nach einer Klärung, gegen welche Regel es verstößt, nicht warum Normenautoren der Antike habe es so gewählt.

    – Benutzer1717828

    17. Mai 2016 um 0:57 Uhr

  • @LightnessRacesinOrbit Die Frage, die Sie beschreiben, wäre wahrscheinlich nicht zum Thema. Ich kann keine sehen technisch Grund, warum es nicht möglich wäre, dies zu implementieren. Ohne eine endgültige Antwort der Autoren der Spezifikation wären alle Antworten meinungsbasiert. Und es würde im Allgemeinen nicht in die Kategorie der “praktischen” oder “beantwortbaren” Fragen fallen (wie das Hilfezentrum angibt, dass wir sie benötigen).

    – jpmc26

    17. Mai 2016 um 7:37 Uhr


  • @LightnessRacesinOrbit Es ist erklärt warum: “weil C-Standard es gesagt hat”. Die Frage, warum diese Regel als definiert definiert ist, wäre nicht zum Thema.

    – Benutzer11153

    17. Mai 2016 um 9:26 Uhr

Die String-Literal-Verkettung wird vom Präprozessor zur Kompilierzeit durchgeführt. Es gibt keine Möglichkeit für diese Verkettung, sich des Wertes von bewusst zu sein test, die nicht bekannt ist, bis das Programm tatsächlich ausgeführt wird. Daher können diese Zeichenfolgenliterale nicht verkettet werden.

Da der allgemeine Fall darin besteht, dass Sie für Werte, die zur Kompilierzeit bekannt sind, keine Konstruktion wie diese haben würden, wurde der C-Standard entwickelt, um die Funktion der automatischen Verkettung auf den grundlegendsten Fall zu beschränken: wenn die Literale buchstäblich direkt nebeneinander stehen .

Aber selbst wenn es diese Einschränkung nicht so formuliert hätte oder wenn die Einschränkung anders aufgebaut wäre, wäre Ihr Beispiel immer noch nicht zu realisieren, ohne die Verkettung zu einem Laufzeitprozess zu machen. Und dafür haben wir die Bibliotheksfunktionen wie z strcat.

  • Ich lese nur Vermutungen. Während das, was Sie sagen, ziemlich gültig ist, können Sie keine Quellen dafür angeben, da es keine gibt. Die einzige Quelle in Bezug auf C ist das Standarddokument, das (obwohl es in vielen Fällen offensichtlich ist) nicht angibt, warum manche Dinge so sind, wie sie sind, sondern nur besagt, dass sie so sein müssen. Es ist also unangebracht, so pingelig in Bezug auf Vlad aus Moskaus Antwort zu sein. Da OP in “Warum ist das so?” – Wo die einzig richtige Antwort lautet “Weil es C ist und C so definiert ist”, ist dies die einzige buchstäblich richtige Antwort.

    – dhein

    17. Mai 2016 um 13:43 Uhr

  • Das ist (zugegeben) erklärungsbedürftig. Aber auch hier wird gesagt, dass Vlads Antwort viel mehr als Erklärung für das Kernproblem dient als Ihre. Nochmals gesagt: Obwohl ich bestätigen kann, dass die Informationen, die Sie geben, zutreffend und korrekt sind, stimme ich Ihren Beschwerden nicht zu. und obwohl ich dich auch nicht als Offtopic bezeichnen würde, ist es aus meiner Sicht mehr Offtopic als Vlads tatsächlich ist.

    – dhein

    17. Mai 2016 um 13:43 Uhr

  • @Zaibis: Die Quelle bin ich. Vlads Antwort ist überhaupt keine Erklärung; es ist lediglich eine Bestätigung der Prämisse der Frage. Sicherlich ist keiner von ihnen “off topic” (vielleicht möchten Sie nachschlagen, was dieser Begriff bedeutet). Aber Sie haben ein Recht auf Ihre Meinung.

    – Leichtigkeitsrennen im Orbit

    17. Mai 2016 um 13:48 Uhr


  • Ich kann nicht unterscheiden, warum diese Antwort für Sie akzeptabel ist und die von @VladfromMoscow nicht, wenn beide dasselbe sagen und wenn seine durch ein Zitat gestützt wird und Ihre nicht.

    – Benutzer207421

    19. Mai 2016 um 2:03 Uhr

  • @EJP: OMG. Dies wieder. Tun sie nicht sagen dasselbe. Er wiederholt die Prämisse der Frage. Meine antwortet darauf. Machen Sie einen Unterschied zwischen den beiden Textteilen; Sie werden sehen, dass sie es sind ziemlich anders.

    – Leichtigkeitsrennen im Orbit

    19. Mai 2016 um 9:21 Uhr

Benutzeravatar von Unsigned
Ohne Vorzeichen

Weil C keine hat string Typ. String-Literale werden kompiliert char Arrays, auf die von a verwiesen wird char* Zeiger.

C erlaubt benachbart Literale kombiniert werden zur Kompilierzeit, wie in Ihrem ersten Beispiel. Der C-Compiler selbst hat einige Kenntnisse über Strings. Aber diese Informationen sind zur Laufzeit nicht vorhanden, und somit kann keine Verkettung stattfinden.

Während des Kompilierungsprozesses wird Ihr erstes Beispiel “übersetzt” in:

int main() {
    static const char char_ptr_1[] = {'H', 'i', 'B', 'y', 'e', '\0'};
    printf(char_ptr_1);
}

Beachten Sie, wie die beiden Zeichenfolgen vom Compiler zu einem einzigen statischen Array kombiniert werden, bevor das Programm überhaupt ausgeführt wird.

Ihr zweites Beispiel wird jedoch in etwa so “übersetzt”:

int main() {
    static const char char_ptr_1[] = {'H', 'i', '\0'};
    static const char char_ptr_2[] = {'B', 'y', 'e', '\0'};
    static const char char_ptr_3[] = {'G', 'o', 'o', 'd', 'b', 'y', 'e', '\0'};
    int test = 0;
    printf(char_ptr_1 (test ? char_ptr_2 : char_ptr_3));
}

Es sollte klar sein, warum dies nicht kompiliert. Der ternäre Operator ? wird zur Laufzeit ausgewertet, nicht zur Kompilierzeit, wenn die “Strings” nicht mehr als solche existieren, sondern nur noch so einfach char Arrays, referenziert von char* Zeiger. Anders als nebenan Zeichenfolgenliteraleangrenzend char-Zeiger sind einfach ein Syntaxfehler.

Wenn Sie wirklich möchten, dass beide Zweige String-Konstanten zur Kompilierzeit erzeugen, die zur Laufzeit ausgewählt werden, benötigen Sie ein Makro.

#include <stdio.h>
#define ccat(s, t, a, b) (

int
main ( int argc, char **argv){
  printf("%s\n", ccat("hello ", argc > 2 , "y'all", "you"));
  return 0;
}

Was ist der Grund dafür?

Ihr Code, der den ternären Operator verwendet, wählt bedingt zwischen zwei Zeichenfolgenliteralen aus. Unabhängig von der bekannten oder unbekannten Bedingung kann dies zur Kompilierzeit nicht ausgewertet werden, sodass es nicht kompiliert werden kann. Auch diese Aussage printf("Hi" (1 ? "Bye" : "Goodbye")); würde nicht kompilieren. Der Grund wird in den obigen Antworten ausführlich erläutert. Eine weitere Möglichkeit z Erstellen einer solchen Aussage mit einem ternären Operator, der zum Kompilieren gültig istwürde auch beinhalten a Format-Tag und das Ergebnis der ternären Operatoranweisung formatiert als zusätzliches Argument zu printf. Sogar dann, printf() Der Ausdruck würde den Eindruck erwecken, diese Zeichenfolgen erst bei und bereits “verkettet” zu haben Laufzeit.

#include <stdio.h>

int main() {
    int test = 0;
    printf("Hi %s\n", (test ? "Bye" : "Goodbye")); //specify format and print as result
}

Benutzeravatar von Peter Mortensen
Peter Mortensen

Im printf("Hi" "Bye"); Sie haben zwei aufeinanderfolgende char-Arrays, die der Compiler zu einem einzigen Array machen kann.

Im printf("Hi" (test ? "Bye" : "Goodbye")); Sie haben ein Array, gefolgt von einem Zeiger auf char (ein Array, das in einen Zeiger auf sein erstes Element umgewandelt wurde). Der Compiler kann das nicht verschmelzen ein Array und ein Zeiger.

1420970cookie-checkWarum erlaubt C keine Verkettung von Zeichenfolgen, wenn der Bedingungsoperator verwendet wird?

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

Privacy policy