Forum: PC-Programmierung Deklaration von main()


von Dennis S. (eltio)


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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dennis S. schrieb:
> size_t strlen ( char const string [ static 1]) ;

Was ist das for eine Sprache?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Johann L. schrieb:
> Dennis S. schrieb:
>> size_t strlen ( char const string [ static 1]) ;
>
> Was ist das for eine Sprache?

Nennt sich C, ist in der Embedded Welt relativ verbreitet 
(http://en.cppreference.com/w/c/language/array).

von Volle (Gast)


Lesenswert?

Dennis S. schrieb:
> Wieso das "argc + 1" in den Klammern?

weil argv ein Array ist mit der größe argc+1  ist

nimm dein Buch und schlage Array nach

von Dennis S. (eltio)


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...

von Clemens L. (c_l)


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.

: Bearbeitet durch User
von NurEinGast (Gast)


Lesenswert?

>  int main ( int argc , char * argv [ argc +1]) ;

Das kann doch nicht klappen.
argc stellt erst zur Laufzeit einen Wert zur Verfügung.
Damit kann man aber kein Array deklarieren.

von Gerhard (Gast)


Lesenswert?

> int main ( int argc , char * argv [ argc +1]) ;
müsste argc nicht zur Compilezeit bekannt sein für dieses Konstrukt?

Gerhard

von Nop (Gast)


Lesenswert?

NurEinGast schrieb:

> argc stellt erst zur Laufzeit einen Wert zur Verfügung.
> Damit kann man aber kein Array deklarieren.

Doch, kann man - als Funktionsargument. Weil es vollkommen egal ist, 
welche Länge da drinsteht, das verflacht ohnehin zu einem Pointer.

von NurEinGast (Gast)


Lesenswert?

Egal ist es - aber mein Compiler mag so was nicht.....

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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

Dann einfach mal die Dokumentation des Compilers lesen und den Support 
für C11 einschalten.

von Dennis S. (eltio)


Lesenswert?

NurEinGast schrieb:
> Egal ist es - aber mein Compiler mag so was nicht.....
1
gcc -Wall -Wextra main.c -std=c99 -pedantic

von Nop (Gast)


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)

von Dennis S. (eltio)


Lesenswert?

Torsten R. schrieb:
> Dann einfach mal die Dokumentation des Compilers lesen und den Support
> für C11 einschalten.

C99 scheint zu genügen (siehe oben).

von Clemens L. (c_l)


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".

von NurEinGast (Gast)


Lesenswert?

Erstaunlich - wieder was gelernt.

"Variable-length arrays" in C99.

Danke für den Hinweis.

von Dennis S. (eltio)


Lesenswert?

Nop schrieb:
> Aber, ja, die main() habe ich auch noch nie auf so eine Weise deklariert
> gesehen.

Das Gefühl habe ich auch. Aber da ich nicht jeden Quellcode der Welt 
kenne...

von Dennis S. (eltio)


Lesenswert?

NurEinGast schrieb:
> Erstaunlich - wieder was gelernt.

Das ist der Grund warum ich gerade "Modern C" lese. Ob man will oder 
nicht: die Praktiken in der Industrie sind dann ja doch oft eher 
"anachronistisch".. oder "bewährt" je nach dem wie bereit man ist sich 
auf Neues einzulassen. :-D

von Nop (Gast)


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.

von Nop (Gast)


Lesenswert?

NurEinGast schrieb:
> Erstaunlich - wieder was gelernt.
>
> "Variable-length arrays" in C99.

Vorsicht, das ist hier IMO eine Verwechslungsfalle. Die Syntax wird 
aufgrund der VLAs akzeptiert, aber das Element selber ist kein VLA, weil 
es als Funktionaparameter gar nicht erst ein Array ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Igrendwie verwirrend wenn ich
1
#include <stdlib.h>
2
3
int func (size_t a, int p[static a])
4
{
5
    return p[a];
6
}

mit
1
gcc -fsyntax-only -std=c99 -Wvla
anfasse, dann bekomme ich:
1
stdin:3:1: warning: ISO C90 forbids variable length array ‘p’ [-Wvla]
2
 int func (size_t a, int p[static a])
3
 ^

von Nop (Gast)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


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.

von Volle (Gast)


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.

von Nop (Gast)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


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.

von Nop (Gast)


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.

von Johann L. (gjlayde) Benutzerseite


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.

von Dennis S. (eltio)


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

von Nop (Gast)


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.

von Mark B. (markbrandis)


Lesenswert?

Was ist jetzt eigentlich die Antwort auf die Frage des Themenerstellers? 
Dass es zwar nicht falsch (weil vom Compiler akzeptiert), aber doch eher 
blödsinnig ist, die main-Funktion so zu deklarieren?
1
int main ( int argc , char * argv [ argc +1]) ;

von Dennis S. (eltio)


Lesenswert?

Mark B. schrieb:
> Dass es zwar nicht falsch (weil vom Compiler akzeptiert), aber doch eher
> blödsinnig ist, die main-Funktion so zu deklarieren?

Ich sehe mich zumindest darin bestätigt, dass es sehr ungewöhnlich ist.

von Dumdi D. (dumdidum)


Lesenswert?

Nop schrieb:
> ist nicht legal.

Wo steht das?

von F. F. (foldi)


Lesenswert?

Dennis S. schrieb:
> int main ( int argc , char * argv [ argc +1]) ;

Ich glaube nicht, dass das da so steht. :-)

von Dennis S. (eltio)


Lesenswert?

F. F. schrieb:
> Dennis S. schrieb:
>> int main ( int argc , char * argv [ argc +1]) ;
>
> Ich glaube nicht, dass das da so steht. :-)

Falls du dich auf das Semikolon beziehst: JEDER hier hat doch verstanden 
worum es geht... Wahrscheinlich habe ich irgendwas vor dem Kopieren 
falsch markiert. Mea Culpa.

Gruß

von Nop (Gast)


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
        ^~

von F. F. (foldi)


Lesenswert?

Dennis S. schrieb:
> Mea Culpa.

Ist nicht nötig. Deswegen der milde Lächler am Ende.
Keinem ist das aufgefallen.

von Volle (Gast)


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.

von Volle (Gast)


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.

von F. F. (foldi)


Lesenswert?

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?
Das muss ich mir bei Gelegenheit mal ganz durchlesen.

von Rolf M. (rmagnus)


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.

von Dennis S. (eltio)


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

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Ich meine die gesamte DOS Command Parameterübergabe hat so die Argumente 
übergeben bekommen Stichwort Commandzeilenparameter.

So konnte der command.com Parameter aus der Commandline an die main in 
"*.cmd" übergeben.

Namaste

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Also hat jetzt jemand ein Beispiel, wo main so deklariert wird??

Dennis S. schrieb:
> int main ( int argc , char * argv [ argc +1]) ;

von Dumdi D. (dumdidum)


Lesenswert?

Nop schrieb:
> Im C-Standard - Arrays sind eben keine Pointer.

Danke! Das Arrays keine Arrays sind war mir theoretisch bekannt, konnte 
mir aber kein Beispiel vorstelleb wo das relevant ist.

von Wilhelm M. (wimalopaan)


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.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


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.

von Wilhelm M. (wimalopaan)


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

von Wilhelm M. (wimalopaan)


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]

von Rolf M. (rmagnus)


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.

von Wilhelm M. (wimalopaan)


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

von Rolf M. (rmagnus)


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.

von Wilhelm M. (wimalopaan)


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)

von Rolf M. (rmagnus)


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.

: Bearbeitet durch User
von Dennis S. (eltio)


Lesenswert?

Wilhelm M. schrieb:
> In welchem Projekt hast Du das denn gefunden?

Das stammt (wie oben schon mal irgendwo geschrieben) aus dem 
(Online-)Buch "Modern C Programming). Aber leider geht durch das Kapern 
fremder Threads schon sehr die Übersicht verloren.

Sonst hätte "Volle" ja sicherlich die Frage schon beantwortet... ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Dennis S. schrieb:
> Wilhelm M. schrieb:
>> In welchem Projekt hast Du das denn gefunden?
>
> Das stammt (wie oben schon mal irgendwo geschrieben) aus dem
> (Online-)Buch "Modern C Programming). Aber leider geht durch das Kapern
> fremder Threads schon sehr die Übersicht verloren.

Hast Du mal den Link? Es gibt gefühlt tausend solcher Online-Bücher ...

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Angehängte Dateien:

Lesenswert?

Beitrag "Re: Deklaration von main()"


Hier hab ich's noch mal gefunden:  TONY ZHANG "Teach Yourself 24 Lessons 
C in 24 hours"

Hatte ich mich doch richtig erinnert.

Namaste

von argc-- (Gast)


Lesenswert?

Seit wann bekommt man argc+1 Strings anstelle von argc Strings?

von Yalu X. (yalu) (Moderator)


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.

: Bearbeitet durch Moderator
von A. S. (Gast)


Lesenswert?

Winfried J. schrieb:
> Hatte ich mich doch richtig erinnert.

Glückwunsch. Aber haben Deine beiden Beiträge hier irgendwas mit dem 
Thread zu tun?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


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

von Wilhelm M. (wimalopaan)


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!

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


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

von Wilhelm M. (wimalopaan)


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!!!

von Yalu X. (yalu) (Moderator)


Lesenswert?

@Winfried:

Dem TE ging es um die (eigentlich überflüssige) Größendeklaration des
Array-Arguments:
1
int main ( int argc , char * argv [ argc +1]) ;
2
                                    ^^^^^^^

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


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

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

argc-- schrieb:
> Seit wann bekommt man argc+1 Strings anstelle von argc Strings?

Man bekommt argc Strings plus einen Nullzeiger als Ende.

von Dennis S. (eltio)


Lesenswert?

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/

von F. F. (foldi)


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 :-))

von Wilhelm M. (wimalopaan)


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...

von Yalu X. (yalu) (Moderator)


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[]);

von Wilhelm M. (wimalopaan)


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.

von a.s (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.