memcpy vs bucle for – ¿Cuál es el camino correcto para copiar una matriz a partir de un puntero?

Tengo una función foo(int[] nums) que entiendo que es esencialmente equivalente a foo(int* nums). Dentro de foo tengo que copiar el contenido de la matriz señalada por numsen algunos int[10] declarado dentro del ámbito de aplicación de la foo. Yo entiendo lo siguiente es válido:

void foo (int[] nums) 
{
    myGlobalArray = *nums
}

Cuál es la forma correcta para copiar la matriz? Debo usar memcpy así:

void foo (int[] nums)
{
    memcpy(&myGlobalArray, nums, 10);
}

o debo utilizar un bucle for?

void foo(int[] nums)
{
    for(int i =0; i < 10; i++)
    {
        myGlobalArray[i] = nums[i];
    }
}

Hay una tercera opción que me estoy perdiendo?

InformationsquelleAutor mjn12 | 2011-01-18

5 Kommentare

  1. 21

    Memcpy probablemente será más rápido, pero lo más probable es que se comete un error de usarlo.
    Se puede depender de qué tan inteligente es tu compilador de optimización es.

    Su código es incorrecto, aunque. Debe ser:

    memcpy(&myGlobalArray, nums, 10 * sizeof(int) );
    • Hey! Por qué Memcpy sería más rápido??
    • Los autores de la biblioteca de c han pasado un montón de tiempo en la optimización de la misma. Si usted escribe el código para hacer la misma cosa, entonces depende de cómo el compilador optimiza tu código.
    • myGlobalArray es la matriz. Debe ser memcpy(myGlobalArray, nums, 10 * sizeof(int));
    • Actualmente muestra lo que has escrito. Tal vez fue editado?
  2. 62

    Sí, la tercera opción es el uso de C++ a construir:

    std::copy(&nums[0], &nums[10], myGlobalArray);

    Con cualquier cuerdo compilador, es:

    • debe ser óptima en la mayoría de los casos (se compila para memcpy() donde sea posible),
    • es de tipo seguro,
    • correctamente enfrenta cuando decide cambiar el tipo de datos a un no-primitivo (es decir, que se llama copia de constructores, etc.),
    • correctamente enfrenta cuando decide cambiar a una clase de contenedor.
    • Es también más rápido: stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy/…
    • Parece que han dejado una importante palabra de ese comentario: «posiblemente»
    • Charlesworth es &nums[10] permitido cuando el tamaño de la matriz es de 10? Sería nums + 10 de trabajo en su lugar?
    • es idéntica a *(nums + 10), así &nums[10] sería &(*(nums + 10)), que el compilador es probable que optimizar a sólo nums + 10. Pero sí, en general, &nums[10] es válido para una matriz de tamaño 10, como se le permite tomar la dirección de 1-pasado-el-fin de una matriz de iteración sólo a los efectos. Simplemente no eliminar esa dirección, por lo que sería un comportamiento indefinido.
  3. 5

    Generalmente hablando, el peor de los casos será en un optimizada para generación de depuración donde memcpy no está en línea y puede realizar otras cordura/assert comprueba que asciende a un pequeño número de instrucciones adicionales vs un bucle for.

    Sin embargo memcpy es generalmente bien implementado para aprovechar cosas como las características intrínsecas etc, pero esto puede variar con el objetivo de la arquitectura y el compilador. Es poco probable que memcpy nunca será peor que para la implementación del bucle.

    La gente a menudo viaje por el hecho de que memcpy tamaños en bytes, y que escribe cosas como estas:

    //wrong unless we're copying bytes.
    memcpy(myGlobalArray, nums, numNums);
    //wrong if an int isn't 4 bytes or the type of nums changed.
    memcpy(myGlobalArray, nums, numNums);
    //wrong if nums is no-longer an int array.
    memcpy(myGlobalArray, nums, numNums * sizeof(int));

    Usted puede protegerse aquí mediante el uso de las características de lenguaje que permiten hacer un cierto grado de reflexión, que es: hacer las cosas en términos de los datos en sí mismos, en lugar de lo que usted sabe acerca de los datos, debido a que en una función genérica que generalmente no saben nada acerca de los datos:

    void foo (int* nums, size_t numNums)
    {
        memcpy(myGlobalArray, nums, numNums * sizeof(*nums));
    }

    Tenga en cuenta que usted no desea que el «&» delante de «myGlobalArray», ya que las matrices automáticamente el decaimiento de los punteros; en realidad estaban copiando «numérica» a la dirección en memoria donde el puntero a la myGlobalArray[0] se celebró.

    (Editar nota: me gustaría error tipográfico había int[] nums cuando me refiero a que no int nums[] pero he decidido que la adición de Matriz C-puntero-equivalencia caos ayudado a nadie, así que ahora es el int *nums 🙂)

    Utilizando memcpy en objetos que pueden ser peligrosos, considere la posibilidad de:

    struct Foo {
        std::string m_string;
        std::vector<int> m_vec;
    };
    
    Foo f1;
    Foo f2;
    f2.m_string = "hello";
    f2.m_vec.push_back(42);
    memcpy(&f1, &f2, sizeof(f2));

    Este es el camino EQUIVOCADO para copiar objetos que no POD (plain old datos). F1 y f2 tienen ahora un std::string, que piensa que es dueño de «hola». Uno de ellos va a colapsar cuando se destruct, y ambos piensan que poseen el mismo vector de enteros que contiene 42.

    La mejor práctica para los programadores de C++ es el uso de std::copy:

    std::copy(nums, nums + numNums, myGlobalArray);

    Nota por Remy Lebeau o desde C++11

    std::copy_n(nums, numNums, myGlobalArray);

    Esto puede hacer que el tiempo de compilación de las decisiones acerca de qué hacer, incluyendo el uso de memcpy o memmove y, potencialmente, utilizando ESS/vector de instrucciones si es posible. Otra ventaja es que si escribes esto:

    struct Foo {
        int m_i;
    };
    
    Foo f1[10], f2[10];
    memcpy(&f1, &f2, sizeof(f1));

    y más tarde en cambiar Foo incluir un std::string, el código se va a romper. Si en lugar de escribir:

    struct Foo {
        int m_i;
    };
    
    enum { NumFoos = 10 };
    Foo f1[NumFoos], f2[NumFoos];
    std::copy(f2, f2 + numFoos, f1);

    el compilador va a cambiar el código para hacer lo correcto sin ningún trabajo adicional para usted, y su código es un poco más legible.

    • en void foo (int[] nums, size_t numNums) utilizando int[] arroja un error en Visual studio 2017. Está bien si yo uso int*. Sin embargo, en ese caso no puedo usar sizeof en la matriz – siempre devolverá sólo el tamaño de puntero.
    • fijo, que era un error tipográfico, la intención de int nums[], pero a su segundo punto, es porque de matriz de puntos de equivalencia. Poner T x[] en una función proto es equivalente a T* x porque C matrices no tienen tiempo de ejecución el tamaño de la información, por lo que la caries a los punteros. c-faq.com/aryptr/aryptrequiv.html
    • también tenga en cuenta que en C++11 y más tarde, hay std::copy_n() así: std::copy_n(nums, numNums, myGlobalArray);
    • agregó 🙂
  4. 1

    Para el rendimiento, el uso memcpy (o equivalentes). Es altamente optimizado código específico de la plataforma para la derivación de lotes de datos en torno rápido.

    Para el mantenimiento, considere lo que usted está haciendo – el bucle for puede ser más legibles y fáciles de entender. (Conseguir un memcpy mal es una ruta rápida a un accidente o peor)

  5. 1

    Esencialmente, mientras que usted está tratando con VAINA tipos (Normal Ol’ de Datos), tales como int, unsigned int, los punteros, los datos sólo de estructuras, etc… que son seguros para el uso de mem*.

    Si la matriz contiene los objetos, utilizar el bucle for, como el operador = puede ser necesaria para asegurar la correcta asignación.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Recent Articles

Python «set» con duplicados/elementos repetidos

Hay una forma estándar de representar un "conjunto" que puede contener elementos duplicados. Como yo lo entiendo, un conjunto tiene exactamente un cero o...

Python: generador de expresión vs rendimiento

En Python, ¿hay alguna diferencia entre la creación de un generador de objetos a través de un generador de expresión versus el uso de...

Cómo exportar/importar la Masilla lista de sesiones?

Hay una manera de hacer esto? O tengo que tomar manualmente cada archivo de Registro? InformationsquelleAutor s.webbandit | 2012-10-23

no distingue mayúsculas de minúsculas coincidentes en xpath?

Por ejemplo, para el xml a continuación <CATALOG> <CD title="Empire Burlesque"/> <CD title="empire burlesque"/> <CD...