2013-07-03 14 views
11

In C, le stringhe sono matrici di caratteri (char *) e i caratteri vengono solitamente memorizzati in char. Ho notato che alcune funzioni della libC prendono come argomento numeri interi anziché caratteri.Perché putchar, toupper, tolower, ecc. Prendono un int invece di un char?

Ad esempio, prendiamo le funzioni toupper() e tolower() che entrambe utilizzano int. La pagina man dice:

Se c non è un valore unsigned char, o EOF, il comportamento di queste funzioni non è definito.

La mia ipotesi è che con un int, toupper e tolower sono in grado di affrontare e unsigned charEOF. Ma in realtà EOF è in pratica (c'è qualche regola sul suo valore?) Un valore che può essere memorizzato con un char, e dal momento che quelle funzioni non trasformano EOF in qualcos'altro, mi chiedo perché lo toupper non prenda semplicemente un char come argomento.

In ogni caso, perché è necessario accettare qualcosa che non sia un carattere (come EOF)? Qualcuno potrebbe fornirmi un caso d'uso pertinente?

Questo è simile con fputc o putchar, che anche rimessa int che viene convertito in un unsigned char comunque.

Sto cercando le motivazioni precise per quella scelta. Voglio essere convinto, non voglio rispondere che non so se qualcuno mi chiede un giorno.

+3

Non so alcuna regola che 'EOF' deve inserirsi in un' char', e vi posso assicurare che 'char' non è garantito per essere firmato, il che rende la vostra discussione sull'utilizzo' char' invece di 'char unsigned' sembra sbagliato. Intendi "firmato char" per tutto il tempo. –

+0

Hai esaminato le implementazioni di queste funzioni. Penso che il parametro 'int' sia per scopi di ottimizzazione, perché la sua dimensione in byte si adatta bene alle dimensioni dei registri del processore. A sua volta, una variabile 'char' di un byte deve essere convertita in' int' dietro la tendina, e questa operazione richiede un po 'di tempo di elaborazione da elaborare. – sgnsajgon

+1

Leggi questo: [Definizione di EOF e come utilizzarlo efficacemente] (http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?id=1043284351&answer=1048865140) –

risposta

7

C11 7,4

L'intestazione <ctype.h> dichiara diverse funzioni utili per la classificazione e mappatura caratteri. In tutti i casi l'argomento è un int, il cui valore deve essere rappresentabile come un carattere senza segno o uguale al valore della macro EOF . Se l'argomento ha altri valori, il comportamento è indefinito.

C11 7.21.1

EOF

che si espande in un numero intero un'espressione costante, con tipo int e un valore negativo , ...

Lo standard C afferma esplicitamente che EOF è sempre un valore iniziale con valore negativo.E inoltre, la signedness del tipo predefinito char dipende dall'implementazione, quindi potrebbe essere firmata e non in grado di memorizzare un valore negativo:

C11 6.2.5

Se un membro della esecuzione base il set di caratteri è memorizzato in un oggetto char , il suo valore è garantito non negativo. Se qualsiasi altro carattere è memorizzato in un oggetto char, il valore risultante è definito dall'implementazione ma deve essere compreso nell'intervallo di valori che è possibile rappresentare in tale tipo.

+0

Una delle mie domande è: perché una funzione che converte una lettera in un'altra dovrebbe accettare qualcosa che non è una lettera? (EOF incluso) –

1

Se c non è un valore di char senza segno, o EOF, il comportamento di queste funzioni non è definito.

Ma EOF è un aspetto negativo int in C e alcune piattaforme (hi ARM!) Hanno char lo stesso unsigned char.

+1

Sì, ma nei luoghi in cui è importante , lo standard C dice "char unsigned o EOF". –

2

BITD un metodo di codifica incluso:

/* example */ 
int GetDecimal() { 
    int sum = 0; 
    int ch; 
    while (isdigit(ch = getchar())) { /* isdigit(EOF) return 0 */ 
    sum *= 10; 
    sum += ch - '0'; 
    } 
    ungetc(ch, stdin); /* If c is EOF, operation fails and the input stream is unchanged. */ 
    return sum; 
} 

ch con il valore di EOF allora potrebbe essere utilizzato in varie funzioni come isalpha(), tolower().

Questo stile ha causato problemi con putchar(EOF) che a mio avviso ha lo stesso come putchar(255).

Il metodo è sconsigliato oggi per vari motivi. Sono preferiti vari modelli come il seguente.

int GetDecimal() { 
    int ch; 
    while (((ch = getchar()) != EOF)) && isdigit(ch)) { 
    ... 
    } 
    ... 
} 
+0

Ho +1 la tua risposta per l'esempio di utilizzo. Ma come hai detto, è scoraggiato, quindi perché "isdigit" dovrebbe accettare qualcosa che non è un personaggio? –

+0

@Maxime Sono certo che è storico che 'isdigit()' accetta '-1'. Concettualmente, non è difficile pensare a EOF come un altro 'char'. Le funzioni di 'isthis ...()' sono spesso implementate con un array di 256 byte, rendendo banale una matrice di 257 byte per accettare anche EOF (-1). Dal momento che è facile e rende il codice più stretto, indietro quando il codice stretto era di valore superiore, è una buona estensione. Ora, con il mantenimento del codice di ogni valore crescente, questo idioma ha perso il favore. – chux