SORU
22 EKİM 2008, ÇARŞAMBA


Nasıl uyumlu hafıza sadece standart kütüphane kullanarak ayrılacak?

Ben sadece bir iş görüşmesi parçası olarak testi bitirdi ve bana tek bir soru bile referans için google kullanarak durdurdu. Stackoverflow ekibi ile neler yapabileceğini görmek istiyorum:

“İşlev 16byte uyumlu bir işaretçi geçirilen gerektirir, ya da çökecek.” memset_16aligned

a) bellek 1024 bayt tahsis ve 16 bayt sınırının hizalayın?< / ^ br . b) memset_16aligned yürüttü sonra bellek Serbest.

{

   void *mem;

   void *ptr;

   // answer a) here

   memset_16aligned(ptr, 0, 1024);

   // answer b) here

}

CEVAP
22 EKİM 2008, ÇARŞAMBA


Orijinal cevap

{
    void *mem = malloc(1024 16);
    void *ptr = ((char *)mem 16) & ~ 0x0F;
    memset_16aligned(ptr, 0, 1024);
    free(mem);
}

Cevap sabit

{
    void *mem = malloc(1024 15);
    void *ptr = ((uintptr_t)mem 15) & ~ (uintptr_t)0x0F;
    memset_16aligned(ptr, 0, 1024);
    free(mem);
}

Açıklama olarak istedi

İlk adım, yeterli boş alan, her ihtimale karşı ayrılamadı. Bellek 16 baytlık hizalanmış (önde gelen bayt adresi 16 katı olması gerekiyor yani) olması gerektiğinden, 16 ek bayt ekleme yeterli olduğunu garanti eder. İlk 16 baytlık bir yerde, 16-byte uyumlu bir işaretçi var. (malloc() yeterince iyi hizalanmış bir işaretçi dönmek gerekiyordu olduğunu unutmayınherhangi biramaç. Ancak, anlamı 'kayıt' olmak üzere diğer şeyler gibi temel türleri— long, double, long double, long long, ve işaretçiler, nesneleri ve işaretçiler fonksiyonlar. Daha özel şeyler, grafik sistemleri ile oynar gibi yaparken, sistemin geri kalanı — bu gibi dolayısıyla sorular ve Cevaplar daha sıkı uyum ihtiyaçları olabilir.)

Bundan sonraki adım dönüştürmek void işaretçi char pointer; GCC rağmen, sen ne yapmak işaretçi aritmetiği işaretçiler void (ve GCC var uyarı seçenekleri için söyle sen ne zaman kötüye). Ekle başlangıç işaretçi 16. malloc() varsayalım inanılmaz derecede kötü hizalanmış işaretçi geri: 0x800001. 16 ekleme 0x800011 verir. Şimdi 16 baytlık sınırı aşağı yuvarlama istiyorum — 0 son 4 biti sıfırlamak istiyorum. 0x0F son 4 bit bir dizi var; bu nedenle, ~0x0F tüm bitleri son dört dışında biri için ayarlanmış. 0x800011 ile kullanılır 0x800010 verir. Diğer uzaklıklar üzerinde yineleme ve aynı aritmetik çalıştığını görebilirsiniz.

Son adım, free(), kolay: her zaman, sadece geri dönmek için free() değeri o malloc(), calloc() realloc() iade için başka bir felaket. Doğru mem Bu değer tutun — sana teşekkür etmek şartıyla. Serbest bırakır.

Son olarak, eğer haberin iç sistem malloc paket, tahmin edeceğiniz üzere o olabilir iyi dönüş 16 baytlık hizalanmış veri (ya da olabilir 8 baytlık hizalı). Eğer 16-byte uyumlu olsaydı, o zaman değerleri ile dink ihtiyacınız olur. Ancak, bu tehlikeli ve non-taşınabilir — malloc diğer paketler farklı asgari dizilişi var, ve bu nedenle farklı bir şey olduğu zaman bir şey varsayarak çekirdek döker yol açacak. Geniş sınırlar dahilinde, bu çözüm taşınabilir.

Başka biriyle uyumlu hafıza için başka bir yol olarak posix_memalign() geçen; o her yerde mevcut değildir, ama genellikle uygulanabilir bu kullanarak bir temel olarak. Uyum 2; diğer sıralanışı messier olan bir güç olduğunu uygun olduğunu unutmayın.

Bir yorum daha — bu kod ayırma başarılı olduğunu kontrol etmez.

Değişiklik

Windows Programmer işaretçiler bit maskesi operasyon yapamayacağını belirtti, ve, gerçekten, GCC (3.4.6 ve 4.3.1 test) böyle şikayet ediyor. Yani, temel kodun değiştirilmiş bir sürümü — bir ana program içine dönüştürülmüş, izler. Ayrıca söylendiği gibi 16 yerine sadece 15 ekleme cüretinde bulundum. C99 çevresinde birçok platformda erişilebilir olması için yeterince uzun zamandan beri uintptr_t kullanıyorum. Eğer printf() tablolar PRIXPTR kullanımı için olmasaydı, 27* *#include <inttypes.h> kullanmak yerine yeterli olur.[Bu kod düzeltme göz ardı ettim ki, ilk Bill K tarafından yıllar önce yapılmış, yineleyen olan C.R. ile işaret etti şimdiye kadar içerir.]

#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void memset_16aligned(void *space, char byte, size_t nbytes)
{
    assert((nbytes & 0x0F) == 0);
    assert(((uintptr_t)space & 0x0F) == 0);
    memset(space, byte, nbytes);  // Not a custom implementation of memset()
}

int main(void)
{
    void *mem = malloc(1024 15);
    void *ptr = (void *)(((uintptr_t)mem 15) & ~ (uintptr_t)0x0F);
    printf("0x" PRIXPTR ", 0x" PRIXPTR "\n", (uintptr_t)mem, (uintptr_t)ptr);
    memset_16aligned(ptr, 0, 1024);
    free(mem);
    return(0);
}

Ve burada 2'nin katları olan boyutları için biraz daha fazla genelleştirilmiş bir versiyonu

#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void memset_16aligned(void *space, char byte, size_t nbytes)
{
    assert((nbytes & 0x0F) == 0);
    assert(((uintptr_t)space & 0x0F) == 0);
    memset(space, byte, nbytes);  // Not a custom implementation of memset()
}

static void test_mask(size_t align)
{
    uintptr_t mask = ~(uintptr_t)(align - 1);
    void *mem = malloc(1024 align-1);
    void *ptr = (void *)(((uintptr_t)mem align-1) & mask);
    assert((align & (align - 1)) == 0);
    printf("0x" PRIXPTR ", 0x" PRIXPTR "\n", (uintptr_t)mem, (uintptr_t)ptr);
    memset_16aligned(ptr, 0, 1024);
    free(mem);
}

int main(void)
{
    test_mask(16);
    test_mask(32);
    test_mask(64);
    test_mask(128);
    return(0);
}

Genel amaçlı içine test_mask() ayırma işlevi dönüştürmek için, ayırıcı tek dönüş değeri birkaç kişi bunların cevaplarını belirttiği gibi serbest adresini kodlamak.

Anketör ile ilgili sorunlar

Uri yorum: Belki de benim sahip [a] okuduğunu anlama sorunu bu sabah, ama eğer mülakat sorum özellikle diyor ki: "Nasıl olur tahsis 1024 bayt bellek" ve net bir şekilde ayırmak daha fazlası. Görüşmeci gelen başarısızlık olmaz mı?

Cevabım 300 karakterlik bir yorum içine sığmaz...

Sanırım bağlıdır. Bence çoğu kişi (ben de dahil) aldı soruya yani "Nasıl olur tahsis alanı olan 1024 bayt veri saklanabilir ve tabanına adresi birden çok 16 bayt". Eğer mülakatı yapan kişi aslında nasıl 1024 bayt (tek) tahsis ve 16 baytlık hizalanmış olabilir anlamına geliyorsa, o zaman seçenekler daha sınırlıdır.

  • Açıkça bir olasılık için tahsis 1024 bayt ve sonra ver Adres 'uyum tedavi'; sorun bu yaklaşım gerçek kullanılabilir alan düzgün belirli (kullanılabilir alan arasında 1008 1024 bayt, ama orada değildi bir mekanizma mevcut belirtin hangi beden), hangi işler daha az yararlı.
  • Başka bir olasılık tam bir bellek ayırıcısı yazıp geri 1024 bayt bloğu uygun hizada olduğundan emin olmak için bekleniyor. Eğer durum buysa, muhtemelen bir operasyon önerilen çözüm yaptığına oldukça benzer yapıyorum ama ayırıcısı içinde Sakla.

Ancak, eğer görüşmeci beklenen de bu tepkiler, ben pek bir şey kalmamış onları tanıması bu çözüm cevaplar bir yakından ilgili soru, ve sonra hususlarında kendi soru üzerine konuşmayı doğru yön. (Ayrıca, eğer mülakatı yapan kişi var gerçekten acımasız, o zaman ben de istemem bu işi; eğer cevap için yeterince hassas bir gerekliliktir atış aşağı içinde alevler olmadan düzeltme, sonra görüşmeci olmayan biri için öyle kimselerdir güvenli.)

Dünya üzerinde hareket eder

Soru Başlığı Son zamanlarda değişti. OlduBeni zorlayan C görüşme söz konusu bellek uyumu çözmek. Revize Başlığı (Nasıl uyumlu hafıza sadece standart kütüphane kullanarak ayrılacak?) talepleri biraz gözden geçirilmiş bir cevap — bu ek sağlar.

C11 (ISO/IEC 9899:2011) aligned_alloc() işlevi eklendi:

7.22.3.1 aligned_alloc işlevi

Özet

#include <stdlib.h>
void *aligned_alloc(size_t alignment, size_t size);

Açıklama
aligned_alloc işlevi olan bir nesne için yer ayırır olan size ile belirtilmiş olan alignment ile belirtilen ve belirsiz. alignment değeri geçerli bir hizalama uygulama tarafından desteklenecek ve size değerini alignment ayrılmaz bir katı olacaktır.

Verir
aligned_alloc işlev bir boş gösterici veya tahsis alanı için bir işaretçi ya da döndürür.

Ve POSIX posix_memalign() tanımlar:

#include <stdlib.h>

int posix_memalign(void **memptr, size_t alignment, size_t size);

AÇIKLAMA

posix_memalign() işlevi size bayt sınırı alignment ile belirtilen uyumlu tahsis ve memptr ayrılan bellek için bir işaretçi dönmek olacaktır. alignment değerini sizeof(void *) ikisi birden bir güç olacaktır.

Başarı ile tamamlayan değer memptr ile işaret alignment katı olacaktır.

Eğer uzay boyutunu istenirse 0, uygulama tanımlı bir davranıştır; değeri memptr dönen bir boş gösterici ya da benzersiz bir işaretçi ya da olacaktır.

free() işlevi daha önce posix_memalign() tarafından ayrılan bellek ayırması olacaktır.

DEĞERİ DÖNDÜRÜR

Başarılı bir şekilde tamamlanması, posix_memalign() sıfır döneceğiz üzerine; aksi halde, bir hata numarası hata belirtmek için iade edilecektir.

Ya da her ikisi de bu soruya şimdi cevap vermek için kullanılabilir, ama sadece POSIX işlevi soru aslında cevap ne zaman bir seçenek olmadı.

Sahne arkasında, yeni uyumlu hafıza fonksiyonu ne kadar aynı işi olarak anlatılan soru hariç, onlar yetenek gücü uyumu daha kolay ve takibini yapmak, başlangıç uyumlu hafıza dahili kodunu değil ile başa çıkmak için özel olarak sadece boşaltır bellek döndürülen ayırma işlevi kullanılır.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Emotional Trancer

    Emotional Tr

    4 Mart 2010
  • Eric Enge

    Eric Enge

    2 Kasım 2009
  • tatermoog

    tatermoog

    2 AĞUSTOS 2006