Deklaration von main()

OP #5014456
Lesenswert?

Hallo zusammen,

ich habe folgendes Codefragment:
1
int main ( int argc , char * argv [ argc +1]) ;

Wieso das "argc + 1" in den Klammern?

Desweiteren
1
size_t strlen ( char const string [ static 1]) ;

Ist es richtig, dass mit "static 1" dem Compiler lediglich mitgeteilt 
wird, dass mindestens ein Argument übergeben wird. Was passiert wenn 
keins übergeben wird. Dann würde er doch auch ohne diese Angabe 
meckern..

Gruß
Dennis
OP #5014485
Lesenswert?

Volle schrieb:
> nimm dein Buch und schlage Array nach

Das kommt aus einem Buch und Arrays kenne ich sehr gut.

Aber:
Absatz 5.1.2.2.1 in N1124 erwähnt es nicht explizit und ich habe noch 
keinen Quelltext (weder kommerziell noch OSS) gesehen wo es so gemacht 
wird.

Ich hoffe ich bekomme nie im Leben diese Arroganz zu behaupten alles zu 
kennen...
#5014518
Lesenswert?

Dennis S. schrieb:
> Absatz 5.1.2.2.1 in N1124 erwähnt es nicht

Aber 6.7.6.2.1 und 6.7.6.3.7 in N1570 (C11):

> In addition to optional type qualifiers and the keyword static, the [
> and ] may delimit an expression or *. [...] The optional type qualifiers
> and the keyword static shall appear only in a declaration of a function
> parameter with an array type, and then only in the outermost array type
> derivation.

> A declaration of a parameter as ‘‘array of type’’ shall be adjusted to
> ‘‘qualified pointer to type’’, where the type qualifiers (if any) are
> those specified within the [ and ] of the array type derivation. If the
> keyword static also appears within the [ and ] of the array type
> derivation, then for each call to the function, the value of the
> corresponding actual argument shall provide access to the first element
> of an array with at least as many elements as specified by the size
> expression.
Gast #5014552
Lesenswert?

NurEinGast schrieb:
> Egal ist es - aber mein Compiler mag so was nicht.....

Kommt vielleicht auch drauf an, ob er erst das wegwirft, was in den 
eckigen Klammern steht (weil: irrelevant), oder ob er den Inhalt erst 
auswertet (und damit scheitert).

Aber, ja, die main() habe ich auch noch nie auf so eine Weise deklariert 
gesehen. Normal ist
1
int main(int argc, char **argv)
#5014555
Lesenswert?

Gerhard schrieb:
> müsste argc nicht zur Compilezeit bekannt sein für dieses Konstrukt?

In einem Funktionsparameter ist das erlaubt, wird aber einfach ignoriert 
(aus historischen Gründen). Sinnvoll wäre es nur zur Dokumentation, ist 
aber natürlich missverständlich.

In C11 kann man "static" hinzufügen, das heißt dann "ich meine es 
ernst".
Gast #5014566
Lesenswert?

Clemens L. schrieb:
> wird aber einfach ignoriert (aus historischen Gründen).

Genauer gesagt deswegen, weil in C die Länge eines Arrays nicht 
Bestandteil des Arrays selber ist und andererseits aber bei 
Funktionsaufrufen nur der Pointer auf das erste Array-Element übergeben 
wird.

> Sinnvoll wäre es nur zur Dokumentation

Nichtmal das, denn wie lang das Arrays ist, das legt ja nicht die 
aufgerufene Funktion fest, sondern der Aufrufer, weil der ja den 
Speicherplatz auch bereitstellen muß.

Zudem tendiert diese Art der Doku besonders schnell zum verrotten, weil 
die Längenangabe da ja egal ist und somit bei Änderung im Aufrufer auch 
nichts weiter auffällt. Man hat dann sehr schnell das Einzige, was 
schlimmer als fehlende Doku ist - falsche Doku.
Persönliche Seite #5014623
Lesenswert?

Nop schrieb:
> Johann L. schrieb:
>
>>
1
#include <stdlib.h>
2
>>
3
>> int func (size_t a, int p[static a])
4
>> {
5
>>     return p[a];
6
>> }
>
> Das return ist übrigens schon ein out-of-bounds-access. Wenn a die Größe
> des Arrays ist, dann reichen seine Elemente von 0 bis a-1.

> If the keyword static also appears within the [ and ] of the array
> type derivation, then for each call to the function, the value of the
> corresponding actual argument shall provide access to the first element
> of an array with at least as many elements as specified by the size
> expression.

Gibt also nur eine Untergrenze an, keine Obergrenze.
Gast #5014629
Lesenswert?

Dennis S. schrieb:
> Volle schrieb:
>> nimm dein Buch und schlage Array nach
>
> Das kommt aus einem Buch und Arrays kenne ich sehr gut.

dann wüstest du aber das [ ]  immer im Zusammenhang mir Arrays 
auftauchen


Früher, als man noch Kommandozeilenprogramme geschrieben hat
so ganz ohne Fenster und Maus
hat gute jeder Entwickler seinen eigenen Parser für argv in der 
Schublade
den er für alle seinen eigenen Progrämmchen verwendet hat. Für jedes 
Programm erweitert und verbessert hat.
Persönliche Seite #5014664
Lesenswert?

Nop schrieb:
> Johann L. schrieb:
>
>> Gibt also nur eine Untergrenze an, keine Obergrenze.
>
> Dann ist es ein kein zwingender, aber ein möglicher
> out-of-bounds-access, weil das Array "p" nur mindestens "a" Elemente
> haben muß. Es sind also auch genau "a" Elemente zulässig, und dann ist
> es out of bounds.

Mag sein.  Aber dann hätte ich zumindest eine mögliche Warnung erwartet, 
die darauf hinweist.  Ansonsten sehe ich keinen Vorteil dieses 
Konstrukts, auch nicht, wie man das für effizienteren Code verwursten 
könnte.
Gast #5014681
Lesenswert?

Ja gut, da hätte man eine Warnung nehmen können.

Aber -Wvla ist sinnlos, weil das immer warnt, wenn VLAs im Code benutzt 
werden - und zwar unabhängig davon, ob sie korrekt benutzt werden oder 
nicht. So erklärt sich auch die Warnung, die da kam.
Persönliche Seite #5014701
Lesenswert?

Nop schrieb:
> Ja gut, da hätte man eine Warnung nehmen können.
>
> Aber -Wvla ist sinnlos, weil das immer warnt, wenn VLAs im Code benutzt
> werden - und zwar unabhängig davon, ob sie korrekt benutzt werden oder
> nicht. So erklärt sich auch die Warnung, die da kam.

Verstehe ich immer noch nicht.  Ob es sich bei einem Array um ein VLA 
handelt kann doch bestenfalls der Aufrufer wissen?

Meinem Verständnis nach ist ein VLA eine Array, dessen Größe zur 
Compilezeit unbekannt ist und das auf dem Stack angelegt wird, z.B.
1
extern void bar (int*);
2

3
void func (size_t s)
4
{
5
    int a[s];
6
    bar (a);
7
}

oder per alloca.

Arrays auf dem Heap, die z.B. per malloc et al. angelegt werden, sind 
demnach keine VLAs.
OP #5014707
Lesenswert?

Volle schrieb:
> dann wüstest du aber das [ ]  immer im Zusammenhang mir Arrays
> auftauchen

Ja... wie gesagt tue ich das sehr gut. Es geht hier aber trotzdem um die 
ungewöhnliche Deklaration von main().

Wie hoch ist der Prozentsatz der dir bekannten Projekte, die diese Art 
der Deklaration nutzen? Wäre ja mal interessant.

Gruß
Dennis
Gast #5014717
Lesenswert?

Johann L. schrieb:

> Verstehe ich immer noch nicht.

Die Warnung ist nur dazu da, daß GCC eben warnt, daß das Feature der 
VLAs überhaupt benutzt wird, so lese ich die GCC-Doku jedenfalls.

> Ob es sich bei einem Array um ein VLA
> handelt kann doch bestenfalls der Aufrufer wissen?

In Deinem Beispiel nicht, denn der Aufrufer muß nichtmal ein Array 
bereitstellen, sondern nur einen Pointer, der auf den Beginn eines 
Speicherbereiches von mindestens "a" ints zeigt.

> Meinem Verständnis nach ist ein VLA eine Array, dessen Größe zur
> Compilezeit unbekannt ist

Ja. Aber im vorliegenden Beispiel war das ja als Funktionsparameter, wo 
es außerhalb der Funktion schon angelegt worden sein muß.

> und das auf dem Stack angelegt wird

Das sagt der C-Standard nicht, weil er den Begriff des Stacks gar nicht 
kennt. GCC implementiert VLAs auf dem Stack, aber er dürfte das 
theoretisch auch per Heap implementieren. Wäre aber wohl ineffizienter.

C selber ist das jedenfalls egal, wichtig ist nur, daß VLAs nur in 
Funktionen angelegt werden können, nicht mit storage class "extern" oder 
"static", und daß sie nicht initialisiert sind, was die effiziente 
Implementation über den Stack erst ermöglicht.

> Arrays auf dem Heap, die z.B. per malloc et al. angelegt werden, sind
> demnach keine VLAs.

Per malloc werden ohnehin keine Arrays angelegt, sondern das sind 
Pointer auf allozierte Speicherbereiche.

Wesentlicher Unterschied:
1
int *ptr;
2
ptr = calloc(a, sizeof(int));
3
ptr++;
ist legal.
1
int arr[a];
2
arr++;

ist nicht legal.
Gast #5015241
Lesenswert?

Dumdi D. schrieb:

> Wo steht das?

Im C-Standard - Arrays sind eben keine Pointer. Die Unterschiede sind 
subtil, aber das ist einer davon.
1
int main (int argc, char **argv)
2
{
3
    int arr[10];
4
    arr++;
5
    return(*arr);
6
}

Der Kommentar von GCC dazu, was auch genau das ist, was man erwarten 
würde:
1
demo.c: In Funktion »main«:
2
demo.c:4:8: Fehler: Als Erhöhungsoperand wird L-Wert erfordert
3
     arr++;
4
        ^~
Gast #5015289
Lesenswert?

Dennis S. schrieb:
> Wie hoch ist der Prozentsatz der dir bekannten Projekte, die diese Art
> der Deklaration nutzen? Wäre ja mal interessant.

80% der Programe unter Dos Windows Unix (und was davon abstammt)
0% in den embeded Programmen, denn da steht startOS in main und kann 
main keie Parameter übergeben

Übrigens auch in den Perl und Java Programmen

jedes gute Programm sollte aus der Kommandozeile auf den Parameter -? 
oder -h regieren.  Und wenn es nur anzeigt wer der Schuldige ist.
Gast #5015293
Lesenswert?

in ISO/IEC 9899:2011
5.1.2.2.1 Programm startup

int main(int argc, char *argv[])  { /* ... */ }
or equivalent; or in some other implementation-defined manner.


int can be replaced by a typedef name defined as int, or the type of 
argv can be written as char ** argv, and so on.
#5015311
Lesenswert?

F. F. schrieb:
> Volle schrieb:
>> int can be replaced by a typedef name defined as int, or the type of
>> argv can be written as char ** argv, and so on.
>
> Mit welchem Sinn?

Den darf sich jeder selber aussuchen. Wer - aus welchem Grund auch immer 
- lieber mit typedefs statt direkt mit den eingebauten Typnamen arbeiten 
will, hat auf diese Weise zumindest die Erlaubnis dazu und wird nicht 
gezwungen, wörtlich "int" hinzuschreiben. Bei char ** argv das gleiche. 
Da wird einfach nur gesagt, dass die angegebene Zeile nicht 100% 
wörtlich so hingeschrieben sein muss, sondern nur zu 100% äquivalent 
dazu sein muss.
OP #5015399
Lesenswert?

Volle schrieb:
> 80% der Programe unter Dos Windows Unix (und was davon abstammt)
> 0% in den embeded Programmen, denn da steht startOS in main und kann
> main keie Parameter übergeben

Kannst du ein paar Projekte verlinken (Github). Ich kann es noch nicht 
so recht glauben. Du hast nicht vergessen, dass es um die "argc + 1" 
geht, oder?

Gruß
Dennis
#5016473
Lesenswert?

In den meisten Fällen "zerfallen" Array-Typen in Zeiger-Typen, Ausnahmen 
sind der sizeof-Operator und der Address-Operator:
1
#include <assert.h>
2

3
void f1(const char* p) {
4
    char first = p[0];
5
}
6

7
void f2(const char (*p)[10]) {
8
    char first = (*p)[0]; // Achtung
9
}
10

11
int main() {
12
    const char s1[] = "abc";
13
    const char s2[10] = "abc";
14
    
15
    f1(s1);
16
    f2(s1); // decay
17

18
    f1(s2);
19
    f2(s2); // decay
20

21
    f1(&s2); // incompatible
22
    f2(&s2); // ok!!! Kein Zerfallen [1]
23
    
24
    assert(s1 == &s1); // gleiche Adressen
25
    assert(s2 == &s2);
26

27
    const char* cs1 = s1;
28
    const char* cs2 = s2; // decay
29

30
    f1(cs1); 
31
    f2(cs2); // decay
32
    
33
    assert(sizeof(s1) == 4);
34
    assert(sizeof(s2) == 10);
35

36
    assert(sizeof(cs1) == sizeof(char*));
37
    assert(sizeof(cs2) == sizeof(char*));
38
}

[1] hier ist zu beachten, dass der Address-Operator den Typ nicht 
zerfallen lässt.

Wie man sieht, ist die Adresse des ersten Elementes und die Adresse des 
Arrays vom Wert identisch, aber der Typ ist eben unterschiedlich, dass 
muss dann in f2() beachtet werden.

D.h. beim "normalen" Aufruf einer Funktion mit einem Array-Bezeichner 
wird als Wert die Adresse des ersten Elementes übergeben und der Type 
zerfällt in Zeiger-auf-Elementtyp. So geht dann die Längeninformation in 
der aufgerufenen Funktion verloren.
#5016476
Lesenswert?

Achim S. schrieb:
> Also hat jetzt jemand ein Beispiel, wo main so deklariert wird??
>
> Dennis S. schrieb:
>> int main ( int argc , char * argv [ argc +1]) ;

Das übersetzt der Compiler zwar, aber die nicht-konstante 
Dimensionsangabe wird nicht beachtet!

Dem main() geht ja ein exec() voraus und hier zerfällt jeder Array-Typ 
schon in einen Zeiger-Typ. Deswegen ist die Dimensionierung einfach 
sinnlos.

Das argv-Array hat in der Tat argc+1 Elemente, denn das letzte Element 
ist als Sentinel der Wert 0 bzw. NULL.
#5016482
Lesenswert?

Dennis S. schrieb:
> Hallo zusammen,
>
> ich habe folgendes Codefragment:
>
>
1
> int main ( int argc , char * argv [ argc +1]) ;
2
>
>
> Wieso das "argc + 1" in den Klammern?

In welchem Projekt hast Du das denn gefunden?

Die möglichen Signaturen von main() sind:
1
int main() in C++ bzw. int main(void) in C
1
int main(int, const char**)
1
int main(int, const char**, const char** e) // e = C-String Array der env-Variablen
#5016487
Lesenswert?

In C++ kann man das ganz besonders schön zeigen, denn die Typ-Ableitung 
erhält auch den Array-Typ:
1
#include <iostream>
2

3
template<typename T, int L>
4
void f(const T (&a)[L]) {
5
    std::cout << __PRETTY_FUNCTION__ << '\n';    
6
}
7

8
template<typename T>
9
void f(const T* a) {
10
    std::cout << __PRETTY_FUNCTION__ << '\n';    
11
}
12

13
int main() {
14
    char s1[] = "abc";
15
    auto s2 = s1;
16
    
17
    f(s1);
18
    f(s2);
19
}

ergibt:

void f(const T (&)[L]) [with T = char; int L = 4]
void f(const T*) [with T = char]
#5016515
Lesenswert?

Wilhelm M. schrieb:
> In welchem Projekt hast Du das denn gefunden?
>
> Die möglichen Signaturen von main() sind:
> int main() in C++ bzw. int main(void) in C

Sowohl in C, als auch in C++ macht das für main überhaupt keinen 
Unterschied.

> int main(int, const char**)

Diese ist äquivalent zu der hier diskutierten Variante.

> int main(int, const char**, const char** e) // e = C-String Array der
> env-Variablen

Diese Version ist systemspezifisch und gibt es in der ISO-Norm nicht. 
Sie ist aber auch nicht verboten.
#5016522
Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> In welchem Projekt hast Du das denn gefunden?
>>
>> Die möglichen Signaturen von main() sind:
>> int main() in C++ bzw. int main(void) in C
>
> Sowohl in C, als auch in C++ macht das für main überhaupt keinen
> Unterschied.

(C): int foo(); deklariert eine Funktion mit variabler Parameterliste
(C): int foo(void); deklariert eine Funktion mit leerer Parameterliste

(C++): int foo(); deklariert eine Funktion mit leerer Parameterliste

siehe auch: http://en.cppreference.com/w/c/language/main_function

>
>> int main(int, const char**)
>
> Diese ist äquivalent zu der hier diskutierten Variante.

Habe auch nichts anderes behauptet.

>
>> int main(int, const char**, const char** e) // e = C-String Array der
>> env-Variablen
>
> Diese Version ist systemspezifisch und gibt es in der ISO-Norm nicht.
> Sie ist aber auch nicht verboten.

Stimmt nicht. Siehe auch: 
http://en.cppreference.com/w/c/language/main_function
#5016538
Lesenswert?

Wilhelm M. schrieb:
> (C): int foo(); deklariert eine Funktion mit variabler Parameterliste
> (C): int foo(void); deklariert eine Funktion mit leerer Parameterliste

Ich weiß, was der Unterschied in C bei Deklarationen mit und ohne void 
in der Parameterliste ist. Das ist relevant für den Aufrufer der 
Funktion. Aber main() wird nicht von mir, sondern automatisch vom 
Startup-Code aufgerufen, daher spielt das da keine Rolle. Deshalb 
schrieb ich oben:

>> [...] macht das für main überhaupt keinen Unterschied.

> (C++): int foo(); deklariert eine Funktion mit leerer Parameterliste

Das (void) ist in C++ aber nicht verboten. Es macht einfach nur das 
gleiche wie eine leere Liste.

>>> int main(int, const char**)
>>
>> Diese ist äquivalent zu der hier diskutierten Variante.
>
> Habe auch nichts anderes behauptet.

Dann verstehe ich nicht, was du mit deiner Mail sagen wolltest.

>>> int main(int, const char**, const char** e) // e = C-String Array der
>>> env-Variablen
>>
>> Diese Version ist systemspezifisch und gibt es in der ISO-Norm nicht.
>> Sie ist aber auch nicht verboten.
>
> Stimmt nicht.

Doch, tut es.

> Siehe auch:
> http://en.cppreference.com/w/c/language/main_function

Hä? Das bestätigt doch, dass meine Aussage stimmt:
1
int main (void) { body }
2
int main (int argc, char *argv[]) { body }   
3
int main (int argc, char *argv[] , other_parameters ) { body }

other_parameters   -   Implementations may allow additional forms of the 
main function. A very common extension is passing a third argument of 
type char*[] pointing at an array of pointers to the execution 
environment variables.

Diese beiden Sätze haben doch exakt die gleiche Aussage wie das, was ich 
oben geschrieben habe.
#5016560
Lesenswert?

Rolf M. schrieb:
>
> Das (void) ist in C++ aber nicht verboten. Es macht einfach nur das
> gleiche wie eine leere Liste.

Habe ich auch nicht behauptet.

>>> Diese Version ist systemspezifisch und gibt es in der ISO-Norm nicht.

Doch, steht doch da.

> Diese beiden Sätze haben doch exakt die gleiche Aussage wie das, was ich
> oben geschrieben habe.

Nein, Du hast geschrieben, dass es sie im Standard nicht gibt! Der 
Standard kennt mindestens 3 Varianten:
1
int main (void) { body }  (1)  
2
int main (int argc, char *argv[]) { body }  (2)  
3
int main (int argc, char *argv[] , other_parameters ) { body }  (3)  
4
/* another implementation-defined signature */  (4)
#5016575
Lesenswert?

Wilhelm M. schrieb:
> Rolf M. schrieb:
>>
>> Das (void) ist in C++ aber nicht verboten. Es macht einfach nur das
>> gleiche wie eine leere Liste.
>
> Habe ich auch nicht behauptet.

Du hattest oben explizit unterschieden zwischen C und C++ und angemerkt, 
dass es in C mit und in C++ ohne void zu schreiben ist. Ich hab nur 
darauf hingewiesen, dass diese Unterscheidung nicht nötig ist.

Wilhelm M. schrieb:
>> Diese beiden Sätze haben doch exakt die gleiche Aussage wie das, was ich
>> oben geschrieben habe.
>
> Nein, Du hast geschrieben, dass es sie im Standard nicht gibt!

Das ist auch richig.

> Der Standard kennt mindestens 3 Varianten:
> int main (void) { body }  (1)
> int main (int argc, char *argv[]) { body }  (2)
> int main (int argc, char *argv[] , other_parameters ) { body }  (3)
> /* another implementation-defined signature */  (4)

Ah, jetzt sehe ich erst, dass es hier (1) bis (4) gibt. Ich hatte (3) 
und (4) als eins gelesen. Die Variante (3) gibt es so in ISO C nicht. 
Wozu auch? Sie ist eine Form der Variante (4).
Hier mal der original-Wortlaut aus dem letzten Draft von C11, der 
praktisch unverändert schon immer so enthalten ist:

**********************************************************************
The function called at program startup is named main. The implementation 
declares no prototype for this function. It shall be defined with a 
return type of int and with no parameters:

         int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though any 
names may be used, as they are local to the function in which they are 
declared):

         int main(int argc, char *argv[]) { /* ... */ }

or equivalent or in some other implementation-defined manner.
**********************************************************************

Da ist nirgends die Variante 3 explizit erwähnt.
Moderator #5017796
Lesenswert?

Hier gibt es das Buch zum Download:

  http://icube-icps.unistra.fr/img_auth.php/d/db/ModernC.pdf

Der Autor des Buchs verwendet für einige Deklartionen gewisse
Schreibweisen, die er zu Beginn erläutert und begründet. In diesen
Schreibweisen tauchen z.T. Dinge (wie bspw. die Größenangabe beim
argv-Array) auf, die nicht an den Compiler (der sie einfach ignoriert),
sondern an den Programmierer gerichtet sind, und zum besseren
Verständnis des Codes beitragen sollen.

Er sich sich aber bewusst, dass einige Programmierer anders denken als
er und schickt deswegen eine Warnung voraus:

1
Warning to experienced C programmers. If you already have some
2
experience with C programming, this may need some getting used to. Here
3
are some of the things that may provoke allergic reactions. If you
4
happen to break out in spots when you read some code here, try to take a
5
deep breath and let it go.

Bis auf die Stroustrupsche Pointerdeklaration¹ finde ich seine
Vorschläge eigentlich auch ganz sinnvoll.

—————————————
¹) Also "char* name;" anstelle von "char *name;". Aber diese Thema wurde
   schon zur Genüge ausdiskutiert. Manche mögen's eben lieber so, andere
   lieber so.
(Firma: Nisch-Aufzüge) Persönliche Seite #5017803
Lesenswert?

Sollte noch jemand Interesse haben suche ich die CD zum Buch und stelle 
das Beispiel ein aber.

Soviel ist klar, mit der Übergabe einer Arrayadresse vom Typ char und 
der
und der Grösse des Arrays als Parameter lassen sich Parameter von 
Programmdatei zu Programmdatei übergeben ohne das main(*,*) zur Laufzeit 
des Compilers Kenntniss davon haben muss ob überhaupt wissen mus ob und 
wieviele  Parameter übergeben werden sollen

so waren diverse zusätzliche DOS-Command-Befehle nachträglich 
integrierbar ohne command.sys und command.com neu compilieren zu müssen.

Ich tippe bei Unix sieht es ähnlich aus?

Namaste
#5017809
Lesenswert?

Yalu X. schrieb:
>
1
> Warning to experienced C programmers. If you already have some
2
> experience with C programming, this may need some getting used to. Here
3
> are some of the things that may provoke allergic reactions. If you
4
> happen to break out in spots when you read some code here, try to take a
5
> deep breath and let it go.
6
>

Das läuft für mich unter: gut gemeint ist nicht immer gut gemacht. 
Sorry, ich finde: das geht gar nicht!
(Firma: Nisch-Aufzüge) Persönliche Seite #5017811
Lesenswert?

Achim S. schrieb:
> Winfried J. schrieb:
>> Hatte ich mich doch richtig erinnert.
>
> Glückwunsch. Aber haben Deine beiden Beiträge hier irgendwas mit dem
> Thread zu tun?

Ich denke sie beantworten ziemlich exakt die Anfangsfragefrage des TO.

Wobei sein Beispiel wohl eine konkrete Variante zu der von mir im Buch 
wiedergefundenen etwas allgemeineren Darstellung ist.

Namaste
#5017812
Lesenswert?

Winfried J. schrieb:
> Achim S. schrieb:
>> Winfried J. schrieb:
>>> Hatte ich mich doch richtig erinnert.
>>
>> Glückwunsch. Aber haben Deine beiden Beiträge hier irgendwas mit dem
>> Thread zu tun?
>
> Ich denke sie beantworten ziemlich exakt die Anfangsfragefrage des TO.
>
> Wobei sein Beispiel wohl eine konkrete Variante zu der von mir im Buch
> wiedergefundenen etwas allgemeineren Darstellung ist.

Schau Dir doch noch mal die ursprüngliche Frage an!!!
(Firma: Nisch-Aufzüge) Persönliche Seite #5017820
Lesenswert?

o.k.  ich dachte er kommt mit dem Konstrukt grundsätzlich nich ins 
Benehmen.

Wie du schon schriebst "Katz mag mais"

Wohl war der Autor versucht sprechenden Code zu schreiben statt sich der 
Kommentarfunktion zu bedienen. Klar dass, dies bei einigen 
schwarz-weis-Denkern zu Brechreiz führt. Aber das ist ja das tolle an C 
jeder darf so schreiben das niemand es lesen kann, oder so das es auch 
ein Anfänger verstehen könnte. ;)

Ich habe darin gar kein Problem gesehen. und deshal wohl auch die Frage 
anders interpretiert als ihr.

sorry dafür

Namaste
#5017938
Lesenswert?

Yalu X. schrieb:
> Hier gibt es das Buch zum Download

Habe mal rein geschaut.
Sehr schön: Rule B.
:-)
Deswegen mag ich englische Fachbücher so gern.
(Obwohl ich gar kein Englisch kann, wie der Naga (Ableitung von 
Teenager, ist dann Naga geworden, weil es die wirklich gibt) nach einem 
halben Jahr Amerika meinte. Eine halbe Stunde später musste er 
feststellen, dass er es offensichtlich auch nicht kann :-))
#5017942
Lesenswert?

Dennis S. schrieb:
> Wilhelm M. schrieb:
>> Hast Du mal den Link? Es gibt gefühlt tausend solcher Online-Bücher ...
>
> https://gustedt.wordpress.com/2016/11/25/modern-c-is-now-feature-complete/

Wenn man den Text dort (S.14) liest, ist doch alles erläutert. Der Autor 
sagt ja auch, dass das, was er schreibt, zu den oben von mir genannten 
Signaturen äquivalent ist und er seine Schreibweise "nur" gewählt hat, 
um die Annahmen (pointer != 0, mindestens argc + 1 Elemente, etc, ...) 
klarer auszudrücken. Das gilt auch für seine Schreibweise von 
Funktionszeigern.

Leider wird das ja alles vom C-Compiler ignoriert. Insofern nützt es gar 
nichts (ausser vielleicht den flüchtigen Leser zu verwirren).

Ich habe nicht nachgeschaut, ob er den "Zerfall" (decay) von 
Arraybezeichnern oder Funktionsbezeichnern auch erläutert: das wäre m.E. 
das wichtigere (s.o. mein Post zu dem Thema).

Und da kann ich mir leider die Bemerkung nicht verkneifen, dass in C++ 
solche (und viele andere Dinge) wesentlich besser sind: denn 
Schnittstellen, die auf Annahmen beruhen (etwa ein C-String ist eine 
zusammenhängende Folge von char-Elementen mit dem Stringendezeichen '\0' 
als Sentinel) sind schlecht, weil der Compiler Verletzungen dieser 
Annahmen nicht zur Compilezeit entdecken kann.

Bevor jetzt wieder der Sturm der Entrüstung losgeht: ja, natürlich 
brauche ich im C++-Code auch eine freie Funktion main(int, char**), wenn 
ich exec()-Parameter haben möchte...
Moderator #5018094
Lesenswert?

Wilhelm M. schrieb:
> Leider wird das ja alles vom C-Compiler ignoriert. Insofern nützt es gar
> nichts (ausser vielleicht den flüchtigen Leser zu verwirren).

Auch Kommentare werden vom Compiler ignoriert (nicht nur in C, sondern
sogar in C++). Sind auch sie deswegen völlig nutzlos? ;-)

Ich finde es durchaus sinnvoll, bei mehreren äquivalenten Schreibweisen
jeweils diejenige zu verwenden, die die Absicht des Programmierers am
besten ausdrückt.

So würde ich bspw. eine Funktion, die einen Pointer auf ein einzelnes
int entgegennimmt, so deklarieren:

1
void func(int *a);

Wenn sie hingegen ein Array (d.h. einen Pointer auf dessen erste
Element) erwartet, würde ich die Array-Syntax bevorzugen, auch wenn
semantisch kein Unterschied besteht:

1
void func(int a[]);
#5018307
Lesenswert?

Yalu X. schrieb:
> Wilhelm M. schrieb:
>> Leider wird das ja alles vom C-Compiler ignoriert. Insofern nützt es gar
>> nichts (ausser vielleicht den flüchtigen Leser zu verwirren).
>
> Auch Kommentare werden vom Compiler ignoriert (nicht nur in C, sondern
> sogar in C++). Sind auch sie deswegen völlig nutzlos? ;-)

Es gibt zwei Dinge bei Kommentaren zu beachten:

1) Kommentare altern anders als der sie umgebende Code.

2) Kommentiere nur das, was der Code nicht sagt, und nicht das, was der 
Code nicht sagen kann.

zu 1) Bessere Kommentare sind Assertionen.

zu 2) Erst wenn man den Code nicht mehr expressiver gestalten kann, 
sollte man einen Kommentar in Betracht ziehen.

> Ich finde es durchaus sinnvoll, bei mehreren äquivalenten Schreibweisen
> jeweils diejenige zu verwenden, die die Absicht des Programmierers am
> besten ausdrückt.

Natürlich (s.a. 2)!

> So würde ich bspw. eine Funktion, die einen Pointer auf ein einzelnes
> int entgegennimmt, so deklarieren:
>
>
>
1
> void func(int *a);
2
>
>
> Wenn sie hingegen ein Array (d.h. einen Pointer auf dessen erste
> Element) erwartet, würde ich die Array-Syntax bevorzugen, auch wenn
> semantisch kein Unterschied besteht:
>
>
>
1
> void func(int a[]);
2
>

Klar, kann man so machen: jeder findet seine eigenen Code-Konventionen 
eh am besten.

Trotzdem fehlt in func(int a[]) die Längenangabe!

Trotzdem kann der Datentyp keine Aussage über den Unterschied machen. 
Und es ändert nichts an der Tatsache, dass man möglichst viel Semantik 
in die Datentypen legen sollte, damit der Compiler besser prüfen kann. 
Kosten tut das ja bei C++ zur Laufzeit nichts.
#5018377
Lesenswert?

a.s schrieb:
> Wilhelm M. schrieb:
>> Trotzdem kann der Datentyp keine Aussage über den Unterschied machen
>
> Das stimmt zwar ... aber nur so halb. Statische Codeanalyse wie Lint
> könnte dementsprechend konditioniert werden.

Natürlich kann ich mir für jedes fragwürdige Konstrukt einen CodeChecker 
schreiben: clang-libanalyze macht das ja leicht möglich. Auch gleich mit 
der Möglichkeit, das Konstrukt dann umzuschreiben ...

Aber: warum sollte ich das tun?

Besser auf eine Sprache umsteigen, die das gleiche kann aber 
gleichzeitig wesentlich expressiver ist (C++). Und das bedeutet ja 
nicht, dass ich dann OOP im engeren Sinne nutzen muss! Ich kann genauso 
prozedural bleiben wie in C und nur an der ein oder anderen Stelle 
besser werden.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren