簡體   English   中英

用於將固定長度緩沖區復制到結構中的memcpy

[英]memcpy for copying a fixed length buffer into a structure

我有這個示例代碼:

struct
{
    char a[2];
    char b[2];
} buff;

char buffer1[5] = "ABCD";

要將buffer1復制到結構成員,我這樣做:

char c[3],d[3];
memcpy(&buff,buffer1,4);
sprintf(c,"%2.2s",buff.a);
sprintf(d,"%2.2s",buff.b);
printf("c=%s,d=%s",c,d);

當我打印變量c和d時,我正確地將c和d變量中的值變為: c="AB"c="CD"

好吧,我的問題是,即使我正確地得到輸出, memcpy會影響與空字符終止相關的任何事情,還是會產生其他與記憶相關的意外后果?

這里有兩個問題:

1)如評論中所述,您可能忘記在結尾'\\0' (即ASCII中的NUL )終結符字符中包含空格。 printf函數的%s格式說明符期望字符串%s格式有效。 然而,沒有什么能阻止你打印成字符序列,就像這里:

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

struct {
    char a[2];
    char b[2];
} buff;

char buffer1[5] = "ABCD";

int main(void)
{
    memcpy(&buff, buffer1, 4);

    printf("First member: %c%c\n", buff.a[0], buff.a[1]);
    printf("Second member: %c%c\n", buff.b[0], buff.b[1]);

    return 0;
}

2)一個更嚴重的問題是編譯器可能在struct成員之間(以及在最后一個成員之后)包含任意填充 ,因此memcpy可能無法按預期工作。 而不是像那樣復制(因為它可能將數組中的字節放入未使用的“整體”)。 我建議每個成員的個人副本或使用offsetof()宏。

來自N1570 6.7.2.1/15 結構和聯合說明符

結構對象中可能存在未命名的填充,但不是在其開頭。

6.7.2.1/17

結構或聯合的末尾可能有未命名的填充。

因此,您應該將memcpy分成兩個調用,例如:

memcpy(&buff.a, buffer1, 2); /* or replace 2 with sizeof buff.a */
memcpy(&buff.b, buffer1+2, 2);

buffer1以null結尾。 但是, buff的數據成員不是,因為您沒有在它們上附加空終止符。 而且,null終結器沒有空間!

所以,不,它不會影響它,因為它不存在。 當您嘗試使用stdio.h的函數時,您會得到意外的結果,這些函數期望以null結尾的字符串。


另外,你可能想在這里查看我的例子,關於在一個結構中循環,它有點相關。 我建議你一次復制到一個數據成員,而不是一次復制。

這可能無法按預期工作。 結構中的字段之間可能存在填充字節。 它們插入字段之間,以使下一個字段以某個地址偏移量開始。 這主要是CPU的字大小或總線大小,或者是高速緩存對齊的倍數。

即使對於char []也是如此,因為這將允許使用單詞傳輸有效地移動/復制這樣的數組。

對於其他類型,填充很可能,另外你必須關心endianess。

還要記住, memcpy和朋友完全按照他們的名字所暗示的做法:他們在一塊內存上運行。 他們不關心字符串,他們對“字符串”沒有任何想法。 插入任何NUL字節會使它們無用,所以它們不會。

請注意,此方法類似於轉換不兼容的指針類型。 你很安全的地方很少,但大多數時候這是通往地獄的道路(又名未定義的行為 )。

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

struct
{
        char a[2];
        char b[2];
}buff;

int main ( void )
{

        char buffer1[4] = "ABCD";

        memcpy ( &buff , buffer1 , 4 );

        printf ( "\n%s\n ", buff.a );
        printf ( "\n%s\n ", buff.b );

        return ( 0 );
}

o/p-->
 rabi@rabi-VirtualBox:~/rabi/c$ gcc 16.c 
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out 

ABCD

CD
 rabi@rabi-VirtualBox:~/rabi/c$

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

struct
{
        char a[3];
        char b[3];
}buff;

int main ( void )
{
        char buffer1[4] = "ABCD";

        memcpy ( &buff.a , &buffer1[0], 2 );
        buff.a[2]='\0';
        memcpy ( &buff.b , &buffer1[2], 2 );
        buff.b[2]='\0';

        printf ( "\n%s\n ", buff.a );
        printf ( "\n%s\n ", buff.b );

        return ( 0 );
}

o/p--->
 rabi@rabi-VirtualBox:~/rabi/c$ gcc 15.c 
rabi@rabi-VirtualBox:~/rabi/c$ ./a.out 

AB

CD
 rabi@rabi-VirtualBox:~/rabi/c$ 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM