Perché dobbiamo menzionare il tipo di dati della variabile in C

19

Di solito in C, dobbiamo dire al computer il tipo di dati nella dichiarazione delle variabili. Per esempio. nel seguente programma, voglio stampare la somma di due numeri in virgola mobile X e Y.

#include<stdio.h>
main()
{
  float X=5.2;
  float Y=5.1;
  float Z;
  Z=Y+X;
  printf("%f",Z);

}

Ho dovuto dire al compilatore il tipo di variabile X.

  • Can't the compiler determine the type of X on its own?

Sì, lo può fare se faccio questo:

#define X 5.2

Ora posso scrivere il mio programma senza dire al compilatore il tipo di X come:

#include<stdio.h>
#define X 5.2
main()
{
  float Y=5.1;
  float Z;
  Z=Y+X;
  printf("%f",Z);

}  

Quindi vediamo che il linguaggio C ha un qualche tipo di funzionalità, utilizzando il quale può determinare il tipo di dati per conto suo. Nel mio caso ha determinato che X è di tipo float.

  • Why do we have to mention the type of data, when we declare something in main()? Why can't the compiler determine the data type of a variable on its own in main() as it does in #define.
    
posta user106313 06.12.2014 - 11:55
fonte

4 risposte

46

Stai confrontando le dichiarazioni variabili con #define s, che non è corretto. Con #define , si crea una mappatura tra un identificatore e uno snippet di codice sorgente. Il preprocessore C sostituirà quindi tutte le occorrenze di quell'identificatore con lo snippet fornito. Scrivendo

#define FOO 40 + 2
int foos = FOO + FOO * FOO;

finisce per essere la stessa cosa del compilatore come scrivere

int foos = 40 + 2 + 40 + 2 * 40 + 2;

Consideralo come copia e incolla automatizzata.

Inoltre, le variabili normali possono essere riassegnate, mentre una macro creata con #define non può (anche se è possibile re #define it). L'espressione FOO = 7 sarebbe un errore del compilatore, poiché non possiamo assegnare a "rvalues": 40 + 2 = 7 è illegale.

Quindi, perché abbiamo bisogno di tipi? Alcuni linguaggi apparentemente si sbarazzano di tipi, questo è particolarmente comune nei linguaggi di scripting. Tuttavia, di solito hanno qualcosa chiamato "tipizzazione dinamica" in cui le variabili non hanno tipi fissi, ma i valori hanno. Mentre questo è molto più flessibile, è anche meno performante. C ama le prestazioni, quindi ha un concetto di variabili molto semplice ed efficiente:

C'è un intervallo di memoria chiamato "stack". Ogni variabile locale corrisponde a un'area nello stack. Ora la domanda è: quanti byte richiede questa zona? In C, ogni tipo ha una dimensione ben definita che puoi interrogare tramite sizeof(type) . Il compilatore deve conoscere il tipo di ciascuna variabile in modo che possa riservare la giusta quantità di spazio nello stack.

Perché le costanti create con #define non hanno bisogno di un'annotazione di tipo? Non sono memorizzati nello stack. Invece, #define crea snippet riutilizzabili del codice sorgente in un modo leggermente più gestibile rispetto alla copia e incolla. I letterali nel codice sorgente come "foo" o 42.87 sono memorizzati dal compilatore sia inline come istruzioni speciali, sia in una sezione dati separata del binario risultante.

Tuttavia, i letterali hanno tipi. Un valore letterale stringa è un char * . 42 è un int ma può essere utilizzato anche per i tipi più brevi (conversione di restringimento). 42.8 sarebbe un double . Se hai un letterale e vuoi che abbia un tipo diverso (ad es. Per fare 42.8 a float , o 42 an unsigned long int ), puoi usare i suffissi - una lettera dopo il letterale che cambia il modo in cui il il compilatore considera questo letterale. Nel nostro caso, potremmo dire 42.8f o 42ul .

Alcune lingue hanno una digitazione statica come in C, ma le annotazioni sul tipo sono facoltative. Esempi sono ML, Haskell, Scala, C #, C ++ 11 e Vai. Come funziona? Magia? No, questo è chiamato "tipo di inferenza". In C # e Go, il compilatore guarda il lato destro di un compito e ne deduce il tipo. Questo è abbastanza semplice se il lato destro è un valore letterale come 42ul . Quindi è ovvio quale dovrebbe essere il tipo di variabile. Altre lingue hanno anche algoritmi più complessi che tengono conto di come viene usata una variabile. Per esempio. se fai x/2 , x non può essere una stringa ma deve avere un tipo numerico.

    
risposta data 06.12.2014 - 12:29
fonte
4

X nel secondo esempio non è mai un float. Si chiama macro, sostituisce il valore della macro definita 'X' nella sorgente con il valore. Un articolo leggibile su #define è qui .

Nel caso del codice fornito, prima della compilazione il preprocessore cambia il codice

Z=Y+X;

a

Z=Y+5.2;

e questo è ciò che viene compilato.

Ciò significa che puoi anche sostituire quei "valori" con codice come

#define X sqrt(Y)

o anche

#define X Y
    
risposta data 06.12.2014 - 12:25
fonte
1

La risposta breve è C ha bisogno di tipi a causa della cronologia / rappresentazione dell'hardware.

Storia: C è stato sviluppato all'inizio degli anni '70 e inteso come linguaggio per la programmazione di sistemi. Il codice è idealmente veloce e sfrutta al meglio le capacità dell'hardware.

Sarebbe stato possibile dedurre tipi al momento della compilazione, ma i tempi di compilazione già lenti sarebbero aumentati (fare riferimento al fumetto di compilazione di XKCD). per applicare "ciao mondo" per almeno 10 anni dopo che C è stato pubblicato ). I tipi inferenziali in fase di runtime non avrebbero adeguato gli obiettivi della programmazione dei sistemi. L'inferenza di runtime richiede una libreria di runtime aggiuntiva. C è venuto molto prima del primo PC. Che aveva 256 RAM. Non Gigabyte o Megabyte ma Kilobyte.

Nel tuo esempio, se ometti i tipi

   X=5.2;
   Y=5.1;

   Z=Y+X;

Quindi il compilatore avrebbe potuto felicemente capire che X & Y è galleggiante e reso Z lo stesso. In effetti, un compilatore moderno avrebbe anche capito che X & Y non sono necessari e basta impostare Z a 10.3.

Supponiamo che il calcolo sia incorporato in una funzione. Lo scrittore di funzioni potrebbe voler utilizzare la propria conoscenza dell'hardware o il problema da risolvere.

Un double sarebbe più appropriato di un float? Prende più memoria ed è più lento ma la precisione del risultato sarebbe più alta.

Forse il valore di ritorno della funzione potrebbe essere int (o long) perché i decimali non erano importanti, sebbene la conversione da float a int non sia senza costi.

Il valore di ritorno potrebbe anche essere effettuato in modo doppio garantendo che float + float non ecceda.

Tutte queste domande sembrano inutili per la stragrande maggioranza del codice scritto oggi, ma erano vitali quando C è stato prodotto.

    
risposta data 07.01.2015 - 18:59
fonte
0

C non ha inferenza di tipo (questo è ciò che viene chiamato quando un compilatore indovina il tipo di una variabile per te) perché è vecchio. È stato sviluppato nel inizio anni '70

Molti linguaggi più recenti dispongono di sistemi che consentono di utilizzare variabili senza specificare il loro tipo (ruby, javascript, python, ecc.)

    
risposta data 06.12.2014 - 12:30
fonte

Leggi altre domande sui tag