Zuweisung an Konstante

Post Reply
Message
Author
mardem

Zuweisung an Konstante

#1 Post by mardem »

Tag zusammen,

kann sich jemand erklären,warum im nachfolgend aufgeführten Beispiel
eine Zuweisung über den Zeiger 'zeig' an die lokale Konstante 'varia'
möglich ist.
Geschieht die Definition der Konstanten nun global,wird die Zuweisung
erkannt und beim ausführen die Fehlermeldung 'Speicherzugriffsfehler'
ausgegeben.Der Compiler begnügt sich in beiden Fällen nur mit einer
Warnung.Theoretisch dürfte doch auch der lokalen Konstanten kein neuer
Wert zugewiesen werden,oder darf eine Konstante nur global deklariert
und definiert werden?


/***********************************************************************/
/* Demo_Zeiger */
/***********************************************************************/
#include <stdio.h>

int main (void)
{
const int varia = 10;
int *zeig = &varia;
*zeig = 11;
printf(" %3d unzulaessige Zuweisung wurde ausgeführt ",*zeig);
}

/***********************************************************************/

Descartes

Re: Zuweisung an Konstante

#2 Post by Descartes »

Ich habe mal am Programmende noch eine zusätzlich Ausgabe reingeschrieben, die mir die Werte von "varia" und "*zeig" ausgibt:
printf(" varia = %i
zeig = %i
", varia, *zeig);

Ausgaben:

<blockquote><hr>$ gcc -O0 -std=c99 -o m1 main1.c
main1.c: In function `main':
main1.c:6: warning: initialization discards qualifiers from pointer target type
$ ./m1
11 unzulaessige Zuweisung wurde ausgefuehrt
varia = 11
zeig = 11
$<hr></blockquote>
Das Programm wird wieder erwarten fehlerfrei ausgeführt. Durch die Zuweisung über den Zeiger wird "varia" geändert. Scheinbar wird über den Zeiger das "const" umgangen.
Wenn man davon ausgeht, dass über den Umweg eines Zeigers jede lokale Variable verändert werden kann -- unabhängig davon ob sie als "const" deklariert ist -- dann ist dieses Ergebnis durchaus erklärbar.

<blockquote><hr>$ gcc -O1 -std=c99 -o m1 main1.c
main1.c: In function `main':
main1.c:6: warning: initialization discards qualifiers from pointer target type
$ ./m1
11 unzulaessige Zuweisung wurde ausgefuehrt
varia = 10
zeig = 11
$<hr></blockquote>
Interessant hier ist, dass "varia" noch immer den Wert 10 aufweist, während die Zeiger Variable den neuen Wert 11 hat -- obwohl doch beide auf den selben Speicherbereich zeigen?!
Wenn man davon ausgeht, dass selbst über den Umweg eines Zeigers eine als "const" deklarierte Variable nicht verändert werden kann dann ist zumindest erklärbar, warum "varia" zum Programmende noch immer den Anfangswert beinhaltet. Warum allerdings der schreibende Zugriffsversuch auf eine "const" Variable nicht mit einer Fehlermeldung quittiert wurde wissen nur die GCC Macher.
Scheinbar spuckt hier die Optimierungsroutine des GCC in die Suppe und verfälscht das Ergebnis.
Wenn schon dann wenigstens konsequent und auch bei -O1, -O2 und -O3 dem "const" das "const" klauen so dass beide Variablen am Programmende den neuen Wert beinhalten, oder aber das Programm abbrechen.

<blockquote><hr>$ gcc -O2 -std=c99 -o m1 main1.c
main1.c: In function `main':
main1.c:6: warning: initialization discards qualifiers from pointer target type
$ ./m1
11 unzulaessige Zuweisung wurde ausgefuehrt
varia = 10
zeig = 11
$<hr></blockquote>
siehe vorherige Bemerkung

Komisch hierbei, dass der GCC mit -O0 ein anderes Ergebnis bringt, als mit -O1, -O2 oder -O3
Erst wenn man die Zeile "cont int varia = 10;" ausserhalb der main() Routine schreibt (also global) dann wird wie erwartet das Programm zur Laufzeit mit einer Speicherschutzverletztung abgebrochen.

<blockquote><hr>$ gcc -O0 -std=c99 -o m2 main2.c
main2.c: In function `main':
main2.c:7: warning: initialization discards qualifiers from pointer target type
$ ./m2
Bus error
$ <hr></blockquote>
Endlich das erwartete Ergebnis.
Dadurch dass "varia" als "const int" deklariert ist muss jeder Versuch diesen Wert nach der Initialisierung noch nachträglich zu verändern mit einer Fehlermeldung quittiert werden.

mardem

Re: Zuweisung an Konstante

#3 Post by mardem »

Hmm,

trotzdem komisch,eine Konstante sollte(wie der Name schon Ausdrucksstark mitteilt),
unabhänig davon wo sie nun letztlich definiert wurde auch Konstant bleiben.
Merkwürdig ist auch das eine direkte Zuweisung an die Konstante innerhalb der
Hauptfunktion 'main()' möglich ist.Auch bei arithmetischen Operationen mit einem
höheren Datentyp wie dem 'float-typ',der ja letztlich eine interne Typwandlung der als
'const int' deklarierten Konstante bewirken muß,reagiert der Compiler nur mit
Warnungen.

*********************************************************************
konst2.c: In function `main':
konst2.c:15: warning: increment of read-only location
konst2.c:16: warning: assignment of read-only variable `varia'
konst2.c:17: warning: assignment of read-only variable `varia'
*********************************************************************

Das einzige was sich zu einer globalen Definition stark zu ändern scheint
ist die Speicheradresse im Arbeitsspeicher......??

/***********************************************************************/
/* Demo_Zeiger */
/***********************************************************************/
#include <stdio.h>

const int varia_global = 10;

int main(void)
{
printf("

");

const int varia = 10;
const int *const zeig = &varia;

printf(" %3d unzulaessige Zuweisung wurde ausgeführt ",++ *zeig);
printf("
%3d unzulaessige Operation wurde ausgeführt ",varia += 10);
printf("
%3d unzulaessige Operation wurde ausgeführt ",varia += 1.0);
printf("

");
printf("
\tvaria=%d ---> zeiger=%d",varia,*zeig);
printf("
\tSpeicheradresse 'varia' =%X",&varia);
printf("
\tSpeicheradresse 'zeiger' =%X",&zeig);
printf("
\tAdressinfo im Zeiger =%X",zeig);
printf("

");
printf("
\tSpeicheradresse 'varia_global' =%X",&varia_global);
printf("

");
}
/***********************************************************************/

Bleibt mir mir nur noch die Alternative die Konstante global zu definieren.

Descartes

Re: Zuweisung an Konstante

#4 Post by Descartes »

Also einmal mit globaler const...
<blockquote><hr>
/* main1.c */
const int a = 10;
int main()
{
int* b = &a;
*b = 11;
}
<hr></blockquote>

...und einmal als lokaler const...

<blockquote><hr>
/* main2.c */
int main()
{
const int a = 10;
int* b = &a;
*b = 11;
}
<hr></blockquote>

...jetzt mal den nicht-optimierten (-O0) assembler output (hier: PowerPC Assembler) angucken...

$ gcc -O0 -S main1.c main2.c
$ diff -Nur main
<blockquote><pre><font size="1" face="">code:</font><hr><font face="Courier New" size="2">
--- main1.s Sat Jan 3 14:26:35 2004
+++ main2.s Sat Jan 3 14:26:35 2004
@@ -1,11 +1,5 @@
.section __TEXT,__text,regular,pure_instructions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
- .globl _a
-.data
-.literal4
- .align 2
-_a:
- .long 10
.section __TEXT,__text,regular,pure_instructions
.align 2
.align 2
@@ -16,15 +10,11 @@
stmw r30,-8(r1)
stwu r1,-64(r1)
mr r30,r1
- mflr r0
- bcl 20,31,"L00000000001$pb"
-"L00000000001$pb":
- mflr r10
- mtlr r0
- addis r2,r10,ha16(_a-"L00000000001$pb")
- la r2,lo16(_a-"L00000000001$pb")(r2)
- stw r2,32(r30)
- lwz r2,32(r30)
+ li r0,10
+ stw r0,32(r30)
+ addi r0,r30,32
+ stw r0,36(r30)
+ lwz r2,36(r30)
li r0,11
stw r0,0(r2)
mr r3,r0
</font><hr></pre></blockquote>

Descartes

Re: Zuweisung an Konstante

#5 Post by Descartes »

Bin grade über folgendes Posting von Mark Whitley (BusyBox) vom Januar 2002 (!) gestolpert:
<blockquote><hr>
Other Madness
-------------
gcc barfs when you do:

static const int foo = 42;
static int bar = foo; /* gcc err: initializer element is not constant */

Yep, that's right folks, gcc claims that a 'const' variable used as an initializer is _not_constant_. I consider this to be another bug.

I need to remember to take that up with the gcc maintainers one of these days RSN.
<hr></blockquote>

Wenn man das "const int a = 10;" durch ein "<b>static</b> const int a = 10;" ersetzt dann liefern beide Varianten (globales const + lokales const) das gleiche (erwartete) Ergebnis: Absturz.

$ gcc -O0 -std=c99 -o m1 main1.c
$ ./m1
Bus error (core dumped)
$ gcc -O0 -std=c99 -o m1 main2.c
$ ./m2
Bus error (core dumped)
$ gcc -O0 -std=c99 -c main1.c main2.c
$ objdump -D main1.o > main1.dissambled
$ objdump -D main2.o > main2.dissambled
$ diff -Nur main1.dissambled main2.dissambled
keine wesentlichen Unterschiede feststellbar
Schauen wir uns doch jetzt einmal den objdump output an:
$ objdump -D main1.o
<blockquote><pre><font size="1" face="">code:</font><hr><font face="Courier New" size="2">
main1.o: file format elf32-i386-freebsd

Disassembly of section .text:

00000000 <main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 08 sub $0x8,%esp
6: 83 e4 f0 and $0xfffffff0,%esp
9: b8 00 00 00 00 mov $0x0,%eax
e: 29 c4 sub %eax,%esp
10: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
17: 8b 45 fc mov 0xfffffffc(%ebp),%eax
1a: c7 00 0b 00 00 00 movl $0xb,(%eax)
20: a1 00 00 00 00 mov 0x0,%eax
25: c9 leave
26: c3 ret
Disassembly of section .data:
Disassembly of section .rodata:

00000000 <a>:
0: 0a 00 or (%eax),%al
...
</font><hr></pre></blockquote>

Descartes

Re: Zuweisung an Konstante

#6 Post by Descartes »

BTW:
Warum kompiliert der GCC das ganze denn überhaupt?
Der C Compiler wirft bei der Zeiger Zuweisung (Zeile 4) lediglich eine Warnung...

<blockquote><hr>
$ gcc -x c -O0 -o m2p main2.c
main2.c: In function `main':
main2.c:4: warning: initialization discards qualifiers from pointer target type
$
<hr></blockquote>

...während der C++ Compiler hier das ganze sogar mit einer Fehlermeldung abbricht.

<blockquote><hr>
$ gcc -x c++ -O0 -o m2p main2.c
main2.c: In function `int main()':
main2.c:4: error: invalid conversion from `const int*' to `int*'
$
<hr></blockquote>

Post Reply