2010-05-21 14 views
16

(gcc 4.4.4 c89)Quando usare strncpy o memmove?

Ho sempre utilizzato strncpy per copiare le stringhe. Non ho mai usato veramente lo memmove o il memcpy. Tuttavia, mi chiedo solo quando decideresti se utilizzare strncpy, memmove o memcpy?

Il codice che sto scrivendo è per un'applicazione client/server. Nella documentazione usano bcopy. Tuttavia, potrei fare lo stesso con gli altri?

bcopy((char*)server->h_addr, 
     (char*)&serv_addr.sin_addr.s_addr, 
     server->h_length); 

Grazie,

+4

'bcopy' non è una funzione standard, che la rende immediatamente inferiore a quella standard. – AnT

risposta

20

Nessuno ha risposto a tutte le vostre domande.

strncpy() viene utilizzato per copiare i dati da una fonte ad una dest di una dimensione impostata, copia (padding) 0x00 s se un byte 0x00 si trova nella matrice di origine (stringa) prima della fine del buffer. A differenza di strcpy, che copierà per sempre fino a quando non viene trovato un byte 0, anche se detto byte è ben oltre il proprio buffer.

memcpy() viene utilizzato per copiare dall'origine a destinazione indipendentemente dal contenuto di origine. Inoltre, tende ad essere ottimizzato per l'hardware e spesso legge le parole di sistema (int s/long s) alla volta per accelerare la copia quando l'allineamento lo consente.

memmove() viene utilizzato per copiare da una sorgente e da un'area di destinazione sovrapposte (ad esempio spostando il contenuto di una matrice attorno a sé o qualcosa di simile - da qui il mnemonico di movimento). Copie i dati partendo dal retro anziché dal fronte per prevenire la perdita di dati dalle regioni che si sovrappongono ai dati di clobbering prima che possano essere letti. Inoltre, tende ad essere leggermente meno efficiente in quanto di solito non c'è molto hardware che aiuti a copiare i dati dal back to front.

bcopy() e i suoi parenti (bzero e alcuni altri) è una funzione di copia di byte che ho visto di tanto in tanto in terra incorporata. Solitamente, copia i dati un byte alla volta dall'origine alla destinazione per evitare problemi di indirizzo di memoria disallineati, anche se qualsiasi buon memcpy gestirà questo in modo che il suo uso sia abbastanza spesso sospetto.

Buona fortuna!

+4

strncpy non termina la copia in anticipo. strncpy scrive esattamente il numero dato di byte, copiando solo l'inizio della stringa se è troppo lungo, o aggiungendo zeri alla fine della copia per riempire il buffer. –

+1

Poi ho imparato qualcosa di nuovo anche oggi. Pensavo fosse terminato presto. (naviga in rete ...) Guarda lì. Modificando la mia spiegazione sopra ora :) –

+1

@MichaelDorgan Mi sono appena imbattuto in questo. 'memmove()' non è corretto nella risposta. Se l'indirizzo di origine è maggiore dell'indirizzo di destinazione, deve iniziare dal lato anteriore. Se l'indirizzo di origine è più piccolo, deve iniziare dal retro. –

6

strcpy (ed altri metodi str *) arresto quando incontrano un NULL (0) byte. memcpy e le relative funzioni NON si fermano quando incontrano un byte NULL.

Se si dispone di dati binari, è necessario utilizzare memcpy. Nel tuo esempio, stai copiando dati binari, non dati di stringa.

strncpy è un caso speciale in cui interromperà la copia su un byte NULL, ma continuerà comunque a eseguire il pad dell'output con NULL fino alla lunghezza specificata.

+0

+1, abbastanza corretto, anche se si potrebbe obiettare che tutti i dati sono dati binari. ;) – WhirlWind

+2

strncpy non smette di riempire il buffer di destinazione, però. strncpy scrive esattamente il numero dato di byte, copiando solo l'inizio della stringa se è troppo lungo, o aggiungendo zeri alla fine della copia per riempire il buffer. –

+0

Grazie, chiarito strncpy –

4

Usa strncpy() solo se sai che c'è spazio sufficiente per la stringa - perché non garantisce la terminazione nulla ed è troppo entusiasta se la destinazione è molto più corta della stringa di origine (perché vuota la stringa su lunghezza intera). E se si conosce la lunghezza, è possibile utilizzare memmove() ...

Se si conosce la lunghezza delle stringhe, memmove() è una scelta sensata - e nominalmente più veloce di strncpy() perché non ha bisogno di verificare la presenza di valori nulli come va ; copia semplicemente il numero rilevante di byte. (Fingo memcpy() non esiste come può fallire se le aree di origine e di destinazione di sovrapposizione memoria, che memmove() otterranno bene indipendentemente.)

Pensate bcopy() come una variante arcaica delle mem*() funzioni.

+4

C'è in realtà una differenza tra memcpy (dst, src, size) e memmove (dst, src, size) perché memmove "sposta" la memoria - significa: dst e src possono sovrapporsi mentre la sovrapposizione deve essere evitata quando si usa memcpy. – Robert

+0

Non ho menzionato 'memcpy()' - Faccio finta che non esista. –

+2

'memcpy()' è più economico di 'memmove()' nella maggior parte dei casi, come di solito si sa che i buffer di origine e destinazione non si sovrappongono. – Hasturkun

5

Se non è necessario il comportamento del buffer-riempimento delle strncpy ma desidera la sicurezza di non traboccante del buffer, in considerazione strlcpy

Da wikipedia:

strlcpy offre due caratteristiche che sono progettati per aiutare il software gli sviluppatori evitano problemi. La funzione prende la dimensione della destinazione come parametro, evitando il buffer overflow se il parametro size è corretto. Se questa dimensione è maggiore di zero, un byte nul viene sempre scritto nella destinazione, quindi la stringa risultante viene sempre annullata (anche se la stringa di origine è stata troncata per adattarsi).

12

Non si dovrebbe mai usare strncpy (a meno che non si tratti di quella situazione specifica rara per cui è stata introdotta). La funzione non è progettata per essere utilizzata con stringhe a C terminate da zero. Il nome dato a quella funzione è solo un errore storico, e sembra essere la fonte principale della confusione per le persone che tentano di usarlo. strncpy è una funzione introdotta per supportare le cosiddette stringhe "a larghezza fissa", non stringhe a zero. L'utilizzo di strncpy con stringhe a terminazione zero è una cattiva pratica di programmazione, anche se è possibile eseguirla in qualche modo simile a "lavoro" per tale scopo.

Una funzione per la copia di stringa "sicura" di lunghezza limitata non esiste nella libreria C, tuttavia alcune implementazioni lo forniscono con il nome strlcpy, che è già diventato un nome standard di fatto per questa funzione. Se la tua implementazione non fornisce strlcpy, implementalo tu stesso.

Inoltre, è vero che in molti casi è possibile sostituire la funzione str... con le funzioni mem..., ad esempio quando si conosce il numero esatto di caratteri da copiare.

+0

Sicuro? IMHO 'strncpy' non ha nulla a che fare con le stringhe a larghezza fissa, l'unico problema è che' strncpy' non azzera la stringa di destinazione, se la stringa sorgente è più grande della dimensione data (che è la fonte della confusione ..). – Frunsi

+0

@frunsi: assolutamente sicuro. La storia di 'strncpy' è ben nota e ben documentata. Non c'è spazio per alcun "IMHO" qui. La funzione è stata creata per riempire campi di nome file lunghi 14 caratteri in una versione arcaica del file system Unix. Questo è l'unico ruolo per il quale è stato usato in modo significativo e questo è l'unico ruolo per cui è utile. – AnT

+0

Ha due problemi: 1) non termina a zero se la sorgente è lunga, 2) si riempie di zeri fino alla fine del buffer è la fonte è breve. Entrambi sono ovvi e immediati sospiri di stringhe a larghezza fissa, ovviamente. – AnT

2

Se siete alla ricerca di un modo sicuro/veloce per copiare, sono stato felice con la seguente tecnica:

memcpy(dest, src, sizeof (dest)); 
dest[sizeof(dest) - 1] = '\0';  // ensure null termination 

meno efficienti, ma funziona anche per limitare i byte scritti e null-terminare la stringa:

sprintf(dest, sizeof (dest), "%s", src); 

restituisce anche il numero di byte che avrebbe scritto, in modo da poter dire se troncamento ha avuto luogo.

Problemi correlati