標準ライブラリのみを使用して整列メモリを割り当てる方法は?

434
JimDaniel 2008-10-23 13:23.

就職の面接の一環としてテストを終えたところですが、参考のためにGoogleを使用していても、1つの質問で困惑しました。StackOverflowのクルーがそれを使って何ができるかを知りたいです:

このmemset_16aligned関数には、16バイトに整列されたポインターが渡される必要があります。そうしないと、クラッシュします。

a)1024バイトのメモリをどのように割り当て、16バイトの境界に揃えますか?
b)のmemset_16aligned実行後にメモリを解放します。

{    
   void *mem;
   void *ptr;

   // answer a) here

   memset_16aligned(ptr, 0, 1024);

   // answer b) here    
}

16 answers

601
Jonathan Leffler 2008-10-23 13:27.

元の回答

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

正解

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

要求に応じた説明

最初のステップは、万が一の場合に備えて、十分な予備スペースを割り当てることです。メモリは16バイトにアラインされている必要があるため(つまり、先頭のバイトアドレスは16の倍数である必要があります)、16バイトを追加すると、十分なスペースが確保されます。最初の16バイトのどこかに、16バイトに整列されたポインターがあります。(注malloc()十分にするように整列されるポインタを返すことになっているいずれかの。目的が、「任意の」の意味は、基本的なタイプのようなもののために主である- 、longdoublelong double。、long longおよびオブジェクトへのポインタとポインタ機能にあなたがいる場合にはグラフィックシステムで遊ぶなど、より専門的なことを行う場合、システムの他の部分よりも厳密な調整が必要になる可能性があります。したがって、このような質問と回答が必要になります。)

次のステップは、voidポインターをcharポインターに変換することです。GCCにもかかわらず、voidポインターに対してポインター演算を行うことは想定されていません(GCCには、それを悪用したときに通知する警告オプションがあります)。次に、開始ポインタに16を追加します。仮定は、malloc()あなたに信じられないほどひどく整列ポインタが返されました:0x800001。16を加算すると、0x800011になります。ここで、16バイトの境界に切り捨てたいので、最後の4ビットを0にリセットします。0x0Fでは、最後の4ビットが1に設定されています。したがって、~0x0F最後の4つを除くすべてのビットが1に設定されます。そしてそれを0x800011で行うと、0x800010になります。他のオフセットを繰り返し処理して、同じ演算が機能することを確認できます。

最後のステップは、free()常にあなた、そしてだけに、復帰:、簡単でfree()の1という値malloc()calloc()またはrealloc()あなたに戻った-何かが災害です。あなたはmemその価値を保持するために正しく提供しました—ありがとう。無料でリリースします。

最後に、システムのmallocパッケージの内部について知っている場合は、16バイトで整列されたデータ(または8バイトで整列されたデータ)を返す可能性があると推測できます。16バイトにアラインされている場合は、値を使用する必要はありません。ただし、これは危険で移植malloc性がありません。他のパッケージの最小配置は異なるため、何か別のことを行うときに1つのことを想定すると、コアダンプが発生します。広い範囲内で、このソリューションは移植可能です。

posix_memalign()整列されたメモリを取得する別の方法として他の誰かが言及しました。これはどこでも利用できるわけではありませんが、これをベースとして実装できることがよくあります。アラインメントが2の累乗であると便利であることに注意してください。他の配置は厄介です。

もう1つのコメント—このコードは、割り当てが成功したことをチェックしません。

修正

Windowsプログラマーは、ポインターに対してビットマスク操作を実行できないことを指摘しました。実際、GCC(3.4.6および4.3.1でテスト済み)はそのように文句を言います。したがって、基本コードの修正バージョン—メインプログラムに変換されたものが続きます。また、指摘されているように、16ではなく15を追加するという自由も取りました。uintptr_tC99はほとんどのプラットフォームでアクセスできるほど長い間使用されてきたので、私は使用しています。それは使用のためではなかった場合PRIXPTRprintf()のステートメント、それはするのに十分である#include <stdint.h>代わりに使用しました#include <inttypes.h>[このコードには、CRによって指摘された修正が含まれています。これは、数年前にBill Kによって最初に指摘された点を繰り返していましたが、これまで見落としていました。]

#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%08" PRIXPTR ", 0x%08" PRIXPTR "\n", (uintptr_t)mem, (uintptr_t)ptr);
    memset_16aligned(ptr, 0, 1024);
    free(mem);
    return(0);
}

そして、これはわずかに一般化されたバージョンであり、2の累乗のサイズで機能します。

#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%08" PRIXPTR ", 0x%08" 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);
}

test_mask()汎用割り当て関数に変換するには、複数の人が回答で示しているように、アロケーターからの単一の戻り値でリリースアドレスをエンコードする必要があります。

インタビュアーの問題

ウリはコメントしました:たぶん私は今朝[a]読解の問題を抱えていますが、インタビューの質問が具体的に「1024バイトのメモリをどのように割り当てますか」と言っていて、それ以上を明らかに割り当てている場合。それはインタビュアーからの自動的な失敗ではないでしょうか?

私の回答は300文字のコメントに収まりません...

状況によると思います。ほとんどの人(私を含む)は、「1024バイトのデータを格納でき、ベースアドレスが16バイトの倍数であるスペースをどのように割り当てるか」という質問をしたと思います。インタビュアーが実際に1024バイト(のみ)を割り当てて16バイトに揃える方法を意味している場合、オプションはさらに制限されます。

  • 明らかに、1つの可能性は、1024バイトを割り当ててから、そのアドレスに「アライメント処理」を与えることです。このアプローチの問題は、実際の使用可能なスペースが適切に決定されていないことです(使用可能なスペースは1008〜1024バイトですが、どのサイズを指定するために使用できるメカニズムがありませんでした)。
  • もう1つの可能性は、フルメモリアロケータを書き込み、返される1024バイトのブロックが適切に整列されていることを確認することです。その場合、提案されたソリューションとほぼ同じ操作を実行することになりますが、アロケーター内に隠します。

ただし、インタビュアーがこれらの回答のいずれかを期待している場合は、このソリューションが密接に関連する質問に回答していることを認識し、質問を再構成して会話を正しい方向に向けることを期待します。(さらに、面接官が本当にずる賢くなった場合、私はその仕事を望まないでしょう。不十分に正確な要件への答えが修正なしに炎上した場合、面接官は安全に働くことができる人ではありません。)

世界は進む

質問のタイトルが最近変更されました。私を困惑させたのは、Cのインタビューの質問でメモリアライメント解決することでし。改訂されたタイトル(標準ライブラリのみを使用して整列されたメモリを割り当てる方法は?)は、わずかに改訂された回答を要求します—この補遺はそれを提供します。

C11(ISO / IEC 9899:2011)追加機能aligned_alloc()

7.22.3.1aligned_alloc機能

あらすじ

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

説明
このaligned_alloc関数は、配置がalignment、で指定され、サイズがで指定されsize、値が不定であるオブジェクトにスペースを割り当てます。の値はalignment、実装によってサポートされる有効な配置であり、の値はsize、の整数倍でなければなりませんalignment

戻り値
このaligned_alloc関数は、nullポインターまたは割り当てられたスペースへのポインターのいずれかを返します

そしてPOSIXは以下を定義しますposix_memalign()

#include <stdlib.h>

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

説明

このposix_memalign()関数は、でsize指定された境界に整列されたバイトを割り当てalignment、に割り当てられたメモリへのポインタを返しますmemptr。の値はalignment、の2倍の累乗でなければなりませんsizeof(void *)

正常に完了すると、が指す値memptrはの倍数になりalignmentます。

要求されたスペースのサイズが0の場合、動作は実装によって定義されます。で返される値はmemptr、nullポインタまたは一意のポインタのいずれかです。

このfree()関数は、によって以前に割り当てられたメモリの割り当てを解除しますposix_memalign()

戻り値

正常に完了すると、posix_memalign()ゼロを返します。それ以外の場合は、エラーを示すためにエラー番号が返されます。

これらのいずれかまたは両方を使用して質問に回答することができますが、質問に最初に回答したときのオプションはPOSIX関数のみでした。

舞台裏では、新しい整列メモリ関数は、質問で概説したのとほぼ同じ仕事をしますが、整列をより簡単に強制し、コードが整列しないように内部で整列メモリの開始を追跡する機能がある点が異なります特別に対処する必要があります—使用された割り当て関数によって返されたメモリを解放するだけです。

58
Steve Jessop 2008-10-23 14:22.

質問の見方によって、わずかに異なる3つの答えがあります。

1)質問された正確な質問には、Jonathan Lefflerのソリューションで十分です。ただし、16に揃えるには、16バイトではなく15バイトしか必要ありません。

A:

/* allocate a buffer with room to add 0-15 bytes to ensure 16-alignment */
void *mem = malloc(1024+15);
ASSERT(mem); // some kind of error-handling code
/* round up to multiple of 16: add 15 and then round down by masking */
void *ptr = ((char*)mem+15) & ~ (size_t)0x0F;

B:

free(mem);

2)より一般的なメモリ割り当て関数の場合、呼び出し元は2つのポインタ(1つは使用し、もう1つは解放する)を追跡する必要はありません。したがって、整列されたバッファの下に「実際の」バッファへのポインタを格納します。

A:

void *mem = malloc(1024+15+sizeof(void*));
if (!mem) return mem;
void *ptr = ((char*)mem+sizeof(void*)+15) & ~ (size_t)0x0F;
((void**)ptr)[-1] = mem;
return ptr;

B:

if (ptr) free(((void**)ptr)[-1]);

memに15バイトしか追加されなかった(1)とは異なり、実装がmallocからの32バイトのアラインメントを保証する場合、このコードは実際にアラインメントを減らす可能性があることに注意してください(可能性は低いですが、理論的にはC実装は32バイトを持つ可能性があります)整列タイプ)。memset_16alignedを呼び出すだけでよいかどうかは問題ではありませんが、構造体にメモリを使用する場合は問題になる可能性があります。

実装固有のアライメント保証が何であるかをプログラムで決定する方法がないため、これに対する適切な修正が何であるかはわかりません(返されたバッファーが必ずしも任意の構造体に適しているとは限らないことをユーザーに警告する以外)。起動時に2つ以上の1バイトのバッファーを割り当てることができ、表示される最悪のアライメントは保証されたアライメントであると想定します。あなたが間違っているなら、あなたは記憶を浪費します。より良いアイデアを持っている人は、そう言ってください...

[追加:「標準」のトリックは、「最大に整列されたタイプである可能性が高い」の和集合を作成して、必要な整列を決定することです。最大に整列されたタイプは、(C99では) ' long long'、 ' long double'、 ' void *'、または ' void (*)(void)'である可能性があります。を含めると<stdint.h>、おそらくintmax_t代わりに' 'を使用できますlong long(そして、Power 6(AIX)マシンでintmax_tは、128ビット整数型になります)。そのユニオンの配置要件は、単一の文字とそれに続くユニオンを使用して構造体に埋め込むことで決定できます。

struct alignment
{
    char     c;
    union
    {
        intmax_t      imax;
        long double   ldbl;
        void         *vptr;
        void        (*fptr)(void);
    }        u;
} align_data;
size_t align = (char *)&align_data.u.imax - &align_data.c;

次に、要求された配置(例では16)とalign上記で計算された値の大きい方を使用します。

(64ビット)Solaris 10では、結果の基本的な配置malloc()は32バイトの倍数であるように見えます。
]

実際には、整列されたアロケーターは、ハードワイヤードではなく、整列のパラメーターを受け取ることがよくあります。したがって、ユーザーは気になる構造体のサイズ(または、それ以上の2の最小累乗)を渡すと、すべてがうまくいきます。

3)プラットフォームが提供するものを使用します:posix_memalignPOSIXの場合_aligned_malloc、Windows上。

4)C11を使用する場合、最もクリーンな(ポータブルで簡潔な)オプションはaligned_alloc、このバージョンの言語仕様で導入された標準ライブラリ関数を使用することです。

37
florin 2008-10-23 13:36.

posix_memalign()(もちろん、POSIXプラットフォームで)試すこともできます。

20
An̲̳̳drew 2008-10-23 14:46.

これは、「切り上げ」部分への代替アプローチです。最も見事にコード化されたソリューションではありませんが、それは仕事を成し遂げます、そしてこのタイプの構文は少し覚えやすいです(そして2の累乗ではないアライメント値のために働くでしょう)。uintptr_tキャストは、コンパイラをなだめるために必要でした。ポインタ演算は、除算や乗算はあまり好きではありません。

void *mem = malloc(1024 + 15);
void *ptr = (void*) ((uintptr_t) mem + 15) / 16 * 16;
memset_16aligned(ptr, 0, 1024);
free(mem);
19
Shao 2010-08-08 00:36.

残念ながら、C99では、C99に準拠するすべてのC実装間で移植可能な方法で、あらゆる種類のアラインメントを保証することはかなり難しいようです。どうして?ポインタは「バイトアドレス」であることが保証されていないため、フラットメモリモデルで想像できるかもしれません。uintptr_tの表現もそのように保証されておらず、それ自体はとにかくオプションの型です。

単純なバイトアドレスであるvoid *(および定義上はchar *)の表現を使用するいくつかの実装を知っているかもしれませんが、C99では、プログラマーにとっては不透明です。実装は、set { segmentoffset }によってポインタを表す場合があります。ここで、offsetは、「実際には」誰が知っているか、どのような配置を持つことができます。なぜ、ポインタは何らかの形のハッシュテーブルルックアップ値、あるいはリンクリストルックアップ値でさえあり得るのです。境界情報をエンコードできます。

C標準の最近のC1Xドラフトには、_Alignasキーワードがあります。それは少し役立つかもしれません。

C99が提供する唯一の保証は、メモリ割り当て関数が、任意のオブジェクトタイプを指すポインタへの割り当てに適したポインタを返すことです。オブジェクトの配置を指定できないため、明確に定義された移植可能な方法で配置を担当する独自の割り当て関数を実装することはできません。

この主張について間違っているのは良いことです。

15
Adisak 2009-10-22 06:40.

16バイトカウントと15バイトカウントのパディングフロントでは、Nのアラインメントを取得するために追加する必要のある実際の数はmax(0、NM)です。ここで、Mはメモリアロケーターの自然なアラインメントです(両方とも2の累乗です)。

アロケータの最小メモリアライメントは1バイトであるため、15 = max(0,16-1)は控えめな答えです。ただし、メモリアロケータが32ビットのint整列アドレス(これはかなり一般的です)を提供することがわかっている場合は、12をパッドとして使用できます。

これはこの例では重要ではありませんが、12KのRAMを備えた組み込みシステムでは重要である可能性があり、すべてのintが保存されます。

実際に可能な限りすべてのバイトを保存しようとする場合に実装する最良の方法は、マクロとして実装することです。これにより、ネイティブのメモリアライメントをフィードできます。繰り返しますが、これはおそらく、すべてのバイトを保存する必要がある組み込みシステムでのみ役立ちます。

以下の例では、ほとんどのシステムで値1で問題ありませんがMEMORY_ALLOCATOR_NATIVE_ALIGNMENT、32ビットで整列された割り当てを使用する理論上の組み込みシステムでは、次の方法で貴重なメモリを少し節約できます。

#define MEMORY_ALLOCATOR_NATIVE_ALIGNMENT    4
#define ALIGN_PAD2(N,M) (((N)>(M)) ? ((N)-(M)) : 0)
#define ALIGN_PAD(N) ALIGN_PAD2((N), MEMORY_ALLOCATOR_NATIVE_ALIGNMENT)
8
Don Wakefield 2008-10-23 13:42.

おそらく彼らはmemalignの知識に満足していただろうか?そして、ジョナサン・レフラーが指摘しているように、知っておくべき2つの新しい好ましい関数があります。

おっと、フローリンは私をそれに打ち負かしました。ただし、リンク先のmanページを読むと、以前の投稿者が提供した例を理解できる可能性があります。

5
Ian Ollmann 2014-06-05 19:19.

この種のことは、高度にベクトル化されたOS X / iOSライブラリであるAccelerate.frameworkに対して常に行います。このライブラリでは、常にアライメントに注意を払う必要があります。かなりの数のオプションがありますが、そのうちの1つまたは2つは上記で説明していません。

このような小さなアレイの最速の方法は、スタックに貼り付けることです。GCC / clangの場合:

 void my_func( void )
 {
     uint8_t array[1024] __attribute__ ((aligned(16)));
     ...
 }

free()は必要ありません。これは通常、2つの命令です。スタックポインタから1024を減算してから、スタックポインタと-alignmentをANDします。配列の寿命がスタックを超えたか、再帰が機能しているか、スタックスペースが非常に貴重であるため、リクエスターがヒープ上のデータを必要としていた可能性があります。

OS X / iOSでは、malloc / calloc / etcへのすべての呼び出し。常に16バイトに整列されます。たとえば、AVX用に32バイトの整列が必要な場合は、posix_memalignを使用できます。

void *buf = NULL;
int err = posix_memalign( &buf, 32 /*alignment*/, 1024 /*size*/);
if( err )
   RunInCirclesWaivingArmsWildly();
...
free(buf);

何人かの人々は同様に働くC ++インターフェースに言及しました。

ページが2の大きな累乗に整列されることを忘れてはなりません。したがって、ページ整列されたバッファーも16バイト整列されます。したがって、mmap()とvalloc()および他の同様のインターフェースもオプションです。mmap()には、必要に応じて、ゼロ以外のものを使用して事前に初期化されたバッファーを割り当てることができるという利点があります。これらはページ揃えのサイズであるため、これらから最小の割り当てを取得することはできず、最初に触れたときにVM障害が発生する可能性があります。

安っぽい:ガードmallocなどをオンにします。VMはオーバーランをキャッチするために使用され、その境界はページ境界にあるため、このようなサイズがn * 16バイトのバッファーはn * 16バイトに整列されます。

一部のAccelerate.framework関数は、ユーザー指定の一時バッファーを取り込んで、スクラッチスペースとして使用します。ここでは、渡されたバッファーが大幅にずれており、ユーザーが積極的に私たちの生活を苦しめようとしていると想定する必要があります。(私たちのテストケースは、一時バッファーの直前と直後にガードページを貼り付けて、それにもかかわらず下線を引きます。)ここでは、16バイトの整列セグメントを保証するために必要な最小サイズを返し、その後手動でバッファーを整列します。このサイズはdesired_size +アライメント-1です。したがって、この場合は1024 + 16-1 = 1039バイトです。次に、次のように調整します。

#include <stdint.h>
void My_func( uint8_t *tempBuf, ... )
{
    uint8_t *alignedBuf = (uint8_t*) 
                          (((uintptr_t) tempBuf + ((uintptr_t)alignment-1)) 
                                        & -((uintptr_t) alignment));
    ...
}

アライメント1を追加すると、ポインタが最初にアライメントされたアドレスを超えて移動し、-alignment(たとえば、alignment = 16の場合は0xfff ... ff0)とAND演算すると、ポインタがアライメントされたアドレスに戻ります。

他の投稿で説明されているように、16バイトのアラインメントが保証されていない他のオペレーティングシステムでは、より大きなサイズでmallocを呼び出し、後でfree()用にポインタを取っておき、すぐ上で説明したようにアラインして、アラインされたポインタを使用できます。一時バッファの場合について説明します。

align_memsetに関しては、これはかなりばかげています。アラインされたアドレスに到達するために最大15バイトをループインするだけで、その後、最後にいくつかの可能なクリーンアップコードを使用してアラインされたストアに進みます。整列された領域とオーバーラップする整列されていないストアとして(長さが少なくともベクトルの長さである場合)、またはmovmaskdquのようなものを使用して、ベクトルコードのクリーンアップビットを実行することもできます。誰かが怠けているだけです。ただし、インタビュアーがstdint.h、ビット演算子、およびメモリの基礎に慣れているかどうかを知りたい場合は、おそらく妥当なインタビューの質問であるため、不自然な例は許されます。

5
Lutorm 2011-07-15 06:34.

ポインタを整数型に正式に変換することは未定義の動作であるため、私が理解しているように、標準のC99で求められていることを実行することは不可能であるというShaoの回答に誰も投票しなかったことに驚いています。(uintptr_t<->の変換を許可する標準は別として、標準void*uintptr_t値の操作を実行してからそれを元に戻すことを許可していないようです。)

3
neuron 2010-10-13 08:09.

memalign、Aligned-Memory-Blocksの使用は、問題の良い解決策かもしれません。

3
J-a-n-u-s 2016-05-11 11:28.

この質問を読んだときに最初に頭に浮かんだのは、整列された構造体を定義し、それをインスタンス化してから、それを指すことでした。

他の誰もこれを提案しなかったので私が行方不明になっている根本的な理由はありますか?

補足として、charの配列を使用したので(システムのcharが8ビット(つまり1バイト)であると仮定)、__attribute__((packed))必ずしも必要ではないと思います(間違っている場合は訂正してください)が、とにかく。

これは私が試した2つのシステムで機能しますが、コードの有効性に対して誤検知が発生することに気付いていないコンパイラーの最適化がある可能性があります。私gcc 4.9.2はOSXとgcc 5.2.1Ubuntuで使用しました。

#include <stdio.h>
#include <stdlib.h>

int main ()
{

   void *mem;

   void *ptr;

   // answer a) here
   struct __attribute__((packed)) s_CozyMem {
       char acSpace[16];
   };

   mem = malloc(sizeof(struct s_CozyMem));
   ptr = mem;

   // memset_16aligned(ptr, 0, 1024);

   // Check if it's aligned
   if(((unsigned long)ptr & 15) == 0) printf("Aligned to 16 bytes.\n");
   else printf("Rubbish.\n");

   // answer b) here
   free(mem);

   return 1;
}
1
Chris 2013-11-26 03:23.

MacOS X固有:

  1. mallocで割り当てられたすべてのポインターは16バイトに整列されます。
  2. C11がサポートされているため、aligned_malloc(16、size)を呼び出すだけです。

  3. MacOS Xは、起動時にmemset、memcpy、memmoveの個々のプロセッサ用に最適化されたコードを選択し、そのコードは、これまで聞いたことのないトリックを使用して高速化します。99%の確率で、memsetは手書きのmemset16よりも高速に実行されるため、質問全体が無意味になります。

100%ポータブルなソリューションが必要な場合、C11以前には何もありません。ポインタの配置をテストするポータブルな方法がないためです。100%ポータブルである必要がない場合は、

char* p = malloc (size + 15);
p += (- (unsigned int) p) % 16;

これは、ポインタをunsigned intに変換するときに、ポインタの配置が最下位ビットに格納されていることを前提としています。unsigned intに変換すると情報が失われ、実装が定義されますが、結果をポインターに変換し直さないため、それは問題ではありません。

恐ろしい部分はもちろん、元のポインタをどこかに保存して、free()を呼び出す必要があることです。ですから、全体として、私はこのデザインの知恵を本当に疑うでしょう。

0
resultsway 2013-03-26 08:27.

ポインタの下に(16-mod)を追加して、16バイトを追加し、元のptrを16ビットにプッシュすることもできます。

main(){
void *mem1 = malloc(1024+16);
void *mem = ((char*)mem1)+1; // force misalign ( my computer always aligns)
printf ( " ptr = %p \n ", mem );
void *ptr = ((long)mem+16) & ~ 0x0F;
printf ( " aligned ptr = %p \n ", ptr );

printf (" ptr after adding diff mod %p (same as above ) ", (long)mem1 + (16 -((long)mem1%16)) );


free(mem1);
}
0
Deepthought 2013-11-26 04:00.

1バイトを無駄にすることができないという制約がある場合、このソリューションは機能します。注:これが無限に実行される場合があります:D

   void *mem;  
   void *ptr;
try:
   mem =  malloc(1024);  
   if (mem % 16 != 0) {  
       free(mem);  
       goto try;
   }  
   ptr = mem;  
   memset_16aligned(ptr, 0, 1024);
0
user3415603 2014-03-15 04:05.

解決策として、メモリを整列させ、1バイトのメモリを無駄にしないパディングの概念を使用しました。

制約がある場合は、1バイトを無駄にすることはできません。mallocで割り当てられたすべてのポインターは16バイトに整列されます。

C11がサポートされているので、を呼び出すだけaligned_alloc (16, size)です。

void *mem = malloc(1024+16);
void *ptr = ((char *)mem+16) & ~ 0x0F;
memset_16aligned(ptr, 0, 1024);
free(mem);
0
stackguy 2019-11-07 08:46.
size =1024;
alignment = 16;
aligned_size = size +(alignment -(size %  alignment));
mem = malloc(aligned_size);
memset_16aligned(mem, 0, 1024);
free(mem);

これが最も単純な実装であることを願っています。コメントを教えてください。

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

アトランタのドナ・ブラジル:「私があなたに私の話をするとき私を踏まないでください」

アトランタのドナ・ブラジル:「私があなたに私の話をするとき私を踏まないでください」

2017年11月19日にアトランタで開催されたドナブラジルとモーアイボリー(ダグスミスフォトグラフィー)ドナブラジルを見逃すことはありません。

彼らは北朝鮮から脱出した亡命者の胃の中に奇妙な寄生虫を見つけました

彼らは北朝鮮から脱出した亡命者の胃の中に奇妙な寄生虫を見つけました

画像:ゲッティ陰謀愛好家は新しくてエキサイティングなディスカッション資料を持っています:国境を越えて韓国に5発撃たれた北朝鮮の脱北者は寄生虫でいっぱいで、そのうちの1人は南のメディアは、寄生虫を持った北朝鮮の脱北者を見つけることは珍しいことではないと報告している、実際、男性が30以上のタイプを持っていたケースがあった。

パニッシャーの第2話は、複雑な陰謀の網を織り交ぜています

パニッシャーの第2話は、複雑な陰謀の網を織り交ぜています

写真:パニッシャー(Netflix)これらのMarvel Netflixが愛していることが1つあるとすれば、それは複雑な政府や企業の陰謀です。そして、なぜこれらのショーがそのルートを選択するのかを理解するのは簡単です。

最新のBoseヘッドフォンは音楽を聴くためのものではなく、パートナーの鼻を鳴らすためのものです。

最新のBoseヘッドフォンは音楽を聴くためのものではなく、パートナーの鼻を鳴らすためのものです。

あなたのパートナーはチェーンソーのように詮索し、あなたを眠らせませんか?あなたのパートナーはあなたがチェーンソーのように詮索したと主張しますが、あなたが詮索しないので彼らは彼の想像ですか?あなたのケースが何であれ、Bose(はい、ハイエンドオーディオ機器のメーカー)はあなたのために何かを持っています。それらはBoseSleepbudsと呼ばれます。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language