1

プリプロセッサがシンボルを置き換えずにglibcがどのように初期化されるかを理解しようとしています。errnoerrno

私は最初にcsu/errno-loc.ccsu/errno.cに基づいて自分で簡単なバージョンを実装しようとしました:

myerrno.h

#ifndef MYERRNO_H
#define MYERRNO_H

extern int *myerrno_location(void);
#define myerrno (*myerrno_location())

#endif

myerrno.c

#include "myerrno.h"

static int myerrno = 0;

int *myerrno_location(void){
    return &myerrno;
}

ただし、コンパイルしようとすると、次のエラー メッセージが表示されます。

myerrno.c:3:1: error: function ‘myerrno_location’ is initialized like a variable
myerrno.c:3:12: error: static declaration of ‘myerrno_location’ follows non-static declaration
myerrno.h:4:13: note: previous declaration of ‘myerrno_location’ was here

プリプロセッサが3 行目(*myerrno_location(void))に遭遇myerrnoしたときに置換を行っていることがわかります。当然のことながら、これは予期された動作です。

これがglibcにとって問題にならない理由がわかりません。のスレッドセーフな実装は、静的変数errnoの名前を変更せずに、このプリプロセッサ置換の問題をどのように回避しますか?errno

4

1 に答える 1

3

問題の修正は、静的変数の名前を変更するのと同じくらい簡単です。

static int myerrno_variable = 0;

int *myerrno_location(void){
    return &myerrno_variable;
}

すべてのスレッドが同じ にアクセスしているため、バージョンはまだスレッドセーフではないことに注意してくださいmyerrno_variable。実際の実装では、スレッド固有のメモリ ロケーションが返されます。__threadGCC には、ストレージ クラスを提供する拡張機能があります。C.11 は と呼ばれる独自のバージョンを提供しますが、実装によってスレッド サポートが提供されている場合にのみ使用できます (定義さthread_localれているかどうかを調べることで確認できます)。__STDC_NO_THREADS__

static __thread int myerrno_variable_gcc;      /* if using GCC */
static thread_local int my_errno_variable_c11; /* if __STD_NO_THREADS__ isn't defined */

スレッド ローカル機能のない POSIX システムでは、実装は を使用pthread_getspecific()して、各スレッドに割り当てられ、 で設定されたスレッド固有のデータへのポインタを取得できますpthread_setspecific()。詳細については、マニュアルを参照してください。

于 2013-08-02T21:10:35.923 に答える