2015-10-12 18 views
20

Mentre mettendo insieme una funzione a-maiuscolo in C++ ho notato che non ho ricevuto i risultati attesi in C.stringa C maiuscolo in C e C++

funzione

C++

#include <iostream> 
#include <cctype> 
#include <cstdio> 

void strupp(char* beg) 
{ 
    while (*beg++ = std::toupper(*beg)); 
} 

int main(int charc, char* argv[]) 
{ 
    char a[] = "foobar"; 
    strupp(a); 
    printf("%s\n", a); 
    return 0; 
} 

uscita come previsto:

FOOBAR 


funzione C

#include <ctype.h> 
#include <stdio.h> 
#include <string.h> 

void strupp(char* beg) 
{ 
    while (*beg++ = toupper(*beg)); 
} 

int main(int charc, char* argv[]) 
{ 
    char a[] = "foobar"; 
    strupp(a); 
    printf("%s\n", a); 
    return 0; 
} 

L'uscita è il risultato previsto con il primo carattere mancante

OOBAR 

Qualcuno sa il motivo per cui il risultato viene troncato durante la compilazione in C?

+5

E se davvero volevi farlo in 'C++': 'std :: transform (a, a + strlen (a), a, std :: toupper); ' – PaulMcKenzie

+0

Puoi spiegare perché ti aspettavi che questo convertisse una stringa in maiuscolo? Nello specifico, perché ti aspettavi che il lato destro di '=' fosse valutato prima della sinistra? –

+0

Sono grato a tutte le persone che hanno fornito feedback e per le preziose informazioni fornite –

risposta

29

Il problema è che non v'è alcun punto di sequenza in

while (*beg++ = toupper(*beg)); 

comportamento Così abbiamo indefinito. Ciò che il compilatore sta facendo in questo caso sta valutando beg++ prima di toupper(*beg) In C, dove in C++ lo sta facendo nell'altro modo.

+0

Significa che il classico c-string copiando one-liner 'while (* s ++ = * t ++);' ha un comportamento indefinito? –

+3

@markh No poiché si tratta di due variabili diverse. Questo è sinonimo di 'while (* s ++ = * s ++)' – NathanOliver

+0

@SteveJessop In realtà, 'while (* s ++ = * t ++);' ha un comportamento definito anche se 's == t'. La ragione per cui 'strcpy' non è definita con regioni sovrapposte è che' strcpy' non è necessariamente implementato con 'while (* s ++ = * t ++);'. – immibis

15
while (*beg++ = std::toupper(*beg)); 

porta a comportamento non definito.

Se il *beg++ è in sequenza prima o dopo std::toupper(*beg) non è specificato.

La soluzione semplice è quello di utilizzare:

while (*beg = std::toupper(*beg)) 
    ++beg; 
10

La linea

while (*beg++ = toupper(*beg)); 

contiene un effetto collaterale su un'entità che viene utilizzato due volte. Non puoi sapere se l'istruzione ++ è eseguita prima o dopo l'inizio (all'interno del toupper). Sei solo fortunato che entrambe le implementazioni mostrino entrambi i comportamenti, poiché sono abbastanza sicuro che sia lo stesso per C++. (Tuttavia, ci sono stati alcuni cambiamenti delle regole per il C++ 11, che non sono certo - ancora, è un cattivo stile.)

Basta muovere il beg ++ fuori della condizione:

while (*beg = toupper(*beg)) beg++; 
3

con Rispetto alla risposta sopra, la "f" non è mai passata dentro la funzione, dovresti provare ad usare questo:

 while ((*beg = (char) toupper(*beg))) beg++; 
+0

il casting in char era importante in quanto il valore di tipo int potrebbe non rientrare nel tipo di ricevitore char – vishal

+1

Questo cast non ottiene nulla che non succederà senza di esso. – Flexo