マンガでよめる痔のこと・薬のこと

http://www.ncad.co.jp/~komata/c-kouza26.htm

↑のページのコードを自分で書いてみましたが、
確かに概ね書いてる通りに動きました。

共有ライブラリの関数を使用するのに、
ヘッダファイルや関数プロトタイプは不要なのですか?

(動的)リンクの際に、mainより先に
共有ライブラリの関数が先に読み込まれているということですか?






http://d.hatena.ne.jp/sleepy_yoshi/20090510/p1

このQ&Aに関連する最新のQ&A

A 回答 (5件)

>使う前に、定義されていれば、不要でしょうか?


>そうでなければ、プロトタイプ(?)宣言が必要?

使う前に宣言or定義がなければ、使われ方から推測された暗黙の宣言がされるだけです。
この「使う前に宣言or定義」にはライブラリ(共有ライブラリも含む)は含まれません。

gccで-Wallなど指定してコンパイルすれば

warning: implicit declaration of function 'my_func'

と警告されます。他のコンパイラでも同様になるはずです。

今回はたまたま暗黙の宣言で問題なかったというだけです。

>実際に自分でコーディングしてコンパイルして実行しましたが、
>概ね書いてある通りに動きました。

なぜそうなるのかも理解していないのに「実行して思った通りに動いたから」で納得するのは危険。
    • good
    • 0

これは、単に、宣言の無い関数に自動で設定されるプロトタイプと、my_funcにプロトタイプが、たまたま矛盾がなかったにすぎません。



共有ライブラリでも静的なリンクでも同じことです。
cc -c my_func.c -o my_func.o # 静的なオブジェクトにコンパイル
cc main.c -o main my_func.o # 静的にリンク
でも同じ結果になります。
    • good
    • 0

(言語仕様上必須ではないけど) 使う前に宣言 (定義を含む) をすべき, それだけです. 「共有ライブラリ」だろうと「単純にリンクするオブジェクトファイル」だろうと同じ.



あそこにあるのは「たまたまプロトタイプがなくても動く」ものでしかありません. 逆に「プロトタイプがないと困る」関数だったりするとやっぱり変なことになります. 例えば
double foo(int x)
{
return x;
}
だけのファイルから共有ライブラリを作り, それを使って
#include <stdio.h>
int main()
{
printf("%f\n", foo(1));
return 0;
}
を動かしてみてください.
    • good
    • 0

どういう風に共有したいかで違ってきます。


ヘッダファイル内で記述したいというのは極普通の発想ですが、それは静的リンクです。

本ケースは依存関係をプログラム中に記述してしまうと
二重宣言に発展する恐れがあり、少し具合が悪いのです。

依存関係の確認は言語や統合環境によって色々変わってくるのですが、
大抵はパスを指定しておいて、コンパイル時に依存関係を参照して解決します。

共有領域はプログラムの生成時に同時に作成されます。
オブジェクト指向的にいえばmainのインスタンスが生成されると同時に領域が確保されます。
当然、main()本体が実行される以前にそれらは完了していなくてはなりません。
    • good
    • 0

そもそも C では「ヘッダファイル」も「プロトタイプ」も必須じゃないからねぇ....



とはいえ, これは「たまたま」と思った方がいいです. 「ヘッダファイルは作る」「プロトタイプは書く」というクセは付けておくべきでしょう.

あ, その上のサイトの内容は「ちょ~古い」と言っていいから注意してね.

この回答への補足

ご回答ありがとうございます。

必須ではないのは、承知しております。

使う前に、定義されていれば、不要でしょうか?
そうでなければ、プロトタイプ(?)宣言が必要?

実際に自分でコーディングしてコンパイルして実行しましたが、
概ね書いてある通りに動きました。

補足日時:2012/06/05 01:41
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QLinuxのgccのインクルードパス?

Linuxのgccで、インクルードファイルやライブラリのパスを設定する方法が知りたいのですが、gccについて詳しい書籍やサイトがありましたら、教えてください。

gccとccの違いも知りたいです。

例)
#include "example.h"

このままだと、example.hが無いと表示されます。

Aベストアンサー

標準ライブラリのパスは、gccのインストール時に指定して、Cプリプロセッサの中に組み込まれます。

#include "example.h"
は、まずカレントディレクトリを探し、次に gccコマンドラインの -I オプションで指定したディレクトリを探し、最後に標準ライブラリが探されます。

#include <example.h>
は、カレントディレクトリを探さない点が異なります。

ccも基本的には同じですが、Unixの種類によって機能が異なる可能性があります。Linuxの場合はcc=gccです。

QUNIX上のプログラムで使うライブラリの中身を知る方法

過去にUNIX上で動作するプログラムを作成していて、その中で多数の.aや.so(標準では無く、オリジナルのもの。)を使っているのですが、.aや.so内にどのような関数があるのか、もしくはそのライブラリに関係するソース名は何か知る手段ってありませんか?
かなり前のものなので、関数仕様書もmakefileも無いため、何をライブラリとしているのか分からず困っています。
駄目もとで、バイナリエディタで中身を確認してみたのですが、何処の情報がそれを示しているかいまいち分かりませんでした。

Aベストアンサー

No.2 の方がご回答されているように、nm コマンドを使えばシンボルの一覧を表示できます。

(ex.1)
$ nm /usr/local/lib/libssl.so
U ASN1_INTEGER_get
U ASN1_INTEGER_set
U ASN1_check_infinite_end
U ASN1_dup
U ASN1_get_object
U ASN1_object_size
U ASN1_put_object
U BIO_callback_ctrl
U BIO_copy_next_retry
U BIO_ctrl
U BIO_f_buffer
00027db0 T BIO_f_ssl

ただし、U となっているものはライブラリ内で未定義のシンボル (変数や関数) であり、他のライブラリによって解決されなければならないものだったと思います。

また、ライブラリが strip コマンドによって strip されてしまっている場合はシンボルテーブルが削除されてしまうため確認できません。

(ex.2)
$ nm /usr/lib/libstdc++.so.5
nm: /usr/lib/libstdc++.so.5: シンボルがありません

No.2 の方がご回答されているように、nm コマンドを使えばシンボルの一覧を表示できます。

(ex.1)
$ nm /usr/local/lib/libssl.so
U ASN1_INTEGER_get
U ASN1_INTEGER_set
U ASN1_check_infinite_end
U ASN1_dup
U ASN1_get_object
U ASN1_object_size
U ASN1_put_object
U BIO_callback_ctrl
U BIO_copy_next_retry
U BIO_ctrl
U BIO_f_buffer
00027db0 T BIO_f_ssl

ただし、U となって...続きを読む

Qdlopenで目的の*.soファイルをロードできません

以下C++のテストソース2ファイルをコンパイルし実行したのですが、libtest.soをロードすることが出来ません。OSはRed Hat Linux EL4.0WS、カーネルは2.6.9-5です。原因と思しき点がお分かりの方がいれば、教えて頂けますでしょうか。

********** ソースファイル1(libtest.cpp) **********
#include <stdio.h>
#include <stdlib.h>

extern "C" {void printTest();}

void printTest(){
printf(" *** SUCCESS!! *** Java - Native Interface test at INOAC\n");
}

********** ソースファイル2(test.cpp) **********
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
static void (*testFunc)();

int main(){
void *library;
const char * error;

library = dlopen("libtest.so",RTLD_LAZY);
if(library==NULL){
printf("Could not open libtest.so\n");
exit(1);
}
dlerror();

testFunc = (void (*)())dlsym(library,"printTest");
error = dlerror();
if(error){
printf("Could not find the function printTest\n");
exit(1);
}

printf("Test from C;\n");
(*testFunc)();
dlclose(library);
return 0;
}

********** 実行方法 **********
pgCC -fPIC -shared libtest.cpp -o libtest.so
pgCC -ldl test.cpp -o test.exe
setenv LD_LIBRARY_PATH "."
./test.exe

以下C++のテストソース2ファイルをコンパイルし実行したのですが、libtest.soをロードすることが出来ません。OSはRed Hat Linux EL4.0WS、カーネルは2.6.9-5です。原因と思しき点がお分かりの方がいれば、教えて頂けますでしょうか。

********** ソースファイル1(libtest.cpp) **********
#include <stdio.h>
#include <stdlib.h>

extern "C" {void printTest();}

void printTest(){
printf(" *** SUCCESS!! *** Java - Native Interface test at INOAC\n");
}

********** ソースファイル2(tes...続きを読む

Aベストアンサー

dlerror() の使い方を間違えていませんか?

library = dlopen("libtest.so",RTLD_LAZY);
if(library==NULL){
printf("Could not open libtest.so?n");
printf("dlerror: %s?n", dlerror() );
exit(1);

とかするとなんと言ってくるでしょう?

Q#defineの定数を文字列として読み込む

#define A "xxx"
#define B "yyy"
と定義しておいて

scanf("%s", str)
で読み込んだ文字列strが
"xxx"だった場合、"yyy"だった場合のように分岐したいのですが
このとき

if(str == "xxx")
のように中身を指定するのではなく

if(str == AA)
のように定数で分岐させることってできますか?

上記のままではできませんが、何か特別な関数とかでできるのでしょうか?

Aベストアンサー

こんにちは。

やりたいことの解釈ですが、(※勘違いの場合はすみません。)

1)マクロの名前(定義名)が文字列として格納された文字列 str があるとする。
 例)
   #define A "xxx"  //マクロ名=A
   char str[] = "A";   //"A"はマクロ名

2)上記の文字列 str を関数 func に渡す際に、マクロ名ではなくそのマクロで
  定義された文字列を渡したい。
 例)
   func( str );    //←この場合
    ↓
   func( "xxx" );  //←として展開される

ということで宜しいでしょうか?

だとした場合、少し回りくどいやり方かもしれませんが、以下のような文字列
変換用のマクロを定義してみては如何でしょうか?
※基本的には、他の回答者の方と同じように strcmp関数 を使用します。

■マクロ例
==============================
//文字列を定義したマクロ …※1
#define A "xxx"
#define B "yyy"

//引数を文字列として取得するマクロ
#define GETSTR(x) #x

//引数をマクロ名としてそのマクロで定義された文字列を取得するマクロ …※2
//注)<string.h>がインクルードされていることを前提とする
#define STR2MAC(str) \
!strcmp(str,GETSTR(A))? A : \
!strcmp(str,GETSTR(B))? B : str
==============================

上記マクロを使用して、関数 func にマクロ名が格納された文字列 str を
渡す場合は、
   func( STR2MAC( str ) );
のような記述になります。

前提として、※2のマクロ内でstrcmp関数を用いて文字列の照合を行って
いますので、<string.h>のインクルードが必要になります。

また、※1の文字列を定義するマクロの種類(パターン)を増やす場合、
※2のマクロの判定文もそれに合わせて増やす必要があります。

上記のマクロを使用したサンプルソースを下記に掲載致します。
注)エラー処理は行っていません。

■サンプルソース
==============================
#include <stdio.h>
#include <string.h>

//文字列を定義したマクロ
#define A "xxx"
#define B "yyy"

//引数を文字列として取得するマクロ
#define GETSTR(x) #x

//引数をマクロ名としてそのマクロで定義された文字列を取得するマクロ
//注)<string.h>がインクルードされていることを前提とする
#define STR2MAC(str) \
!strcmp(str,GETSTR(A))? A : \
!strcmp(str,GETSTR(B))? B : str

//プロトタイプ
void funcHoge( const char *str );

int main(void)
{
char sArg[128];

printf( "A or B ?>" );
scanf( "%s", sArg );

printf( "string1: %s\n", sArg );
funcHoge( STR2MAC(sArg) );

return 0;
}

void funcHoge( const char *str )
{
printf( "string2: %s\n", str );
}
==============================

■上記サンプルの実行結果
≫実行その1≪
A or B ?>A
string1: A
string2: xxx

≫実行その2≪
A or B ?>B
string1: B
string2: yyy

≫実行その3≪
A or B ?>hoge
string1: hoge
string2: hoge

以上です。

こんにちは。

やりたいことの解釈ですが、(※勘違いの場合はすみません。)

1)マクロの名前(定義名)が文字列として格納された文字列 str があるとする。
 例)
   #define A "xxx"  //マクロ名=A
   char str[] = "A";   //"A"はマクロ名

2)上記の文字列 str を関数 func に渡す際に、マクロ名ではなくそのマクロで
  定義された文字列を渡したい。
 例)
   func( str );    //←この場合
    ↓
   func( "xxx" );  //←として展開される

ということで宜しいでしょう...続きを読む

Qapt-get install ****** でinstallしたものをuninstallするには?

御世話になります。
vncserverだけをinstallするつもりが
誤って
apt-get install vncとうってしまいました。
これをuninstallしたいのですが
どのようにすればよろしいでしょうか?

教えて下さい。

Aベストアンサー

# apt-get remove パッケージ名
では、設定ファイルは削除されずに残ります。

完全に削除するときは、
# apt-get --purge remove パッケージ名
です。

QC++ 構造体の一括初期化 {0}

構造体変数に {0} を代入すると、CString は空文字、 intは0に一括で初期化されるようです。
なんでこんなことが出来るのでしょう?
{0}は何?
仕組みを教えて下さい!!

Aベストアンサー

> 一括初期化関数でも作るしかなさそうですね
static変数を初期化用に用意しておくのはいかが?
http://oshiete.goo.ne.jp/qa/2658268.htmlより
>静的記憶域期間をもつオブジェクトを明示的に初期化しない場合、
>次の規定に従う。
>a) そのオブジェクトの型がポインタ型の場合、空ポインタに初期化する。
>b) そのオブジェクトの型が算術型の場合、(正または符号なしの)0に初期化する。
>c) そのオブジェクトが集成体の場合、各メンバにa)~d)の規定を(再帰的に)
>適用し初期化する。
>d) そのオブジェクトが共用体の場合、最初の名前つきメンバにa)~d)の規定を
>(再帰的に)適用し初期化する。

なので、zero初期化されていることが、規格で保証されます。

typedef struct hoge_struct
{
 int a;
 int b;
} hoge_struct;

static hoge_struct initializer; //初期化用変数。値は変えない。

int main(void)
{
 hoge_struct hoge;
 hoge = initializer;
 return 0;
}
真っ白に何度も初期化したいなら、こんな感じでどうでしょう?
関数を用意して初期化すると、構造体のメンバが増えると関数も修正しないといけない
ですが、これだと関数を変更しなくてすむし。

> 一括初期化関数でも作るしかなさそうですね
static変数を初期化用に用意しておくのはいかが?
http://oshiete.goo.ne.jp/qa/2658268.htmlより
>静的記憶域期間をもつオブジェクトを明示的に初期化しない場合、
>次の規定に従う。
>a) そのオブジェクトの型がポインタ型の場合、空ポインタに初期化する。
>b) そのオブジェクトの型が算術型の場合、(正または符号なしの)0に初期化する。
>c) そのオブジェクトが集成体の場合、各メンバにa)~d)の規定を(再帰的に)
>適用し初期化する。
>d) そのオブジェクトが共用...続きを読む

Qfgetsで拾われる改行文字を削除したい

お世話になります

 C言語初心者のものです。今課題でC言語を用いたプログラミングを
Fedora上でやっています。問題は、fgetsでテキストファイルから、取得
した文字列の中から改行文字を削除できないことです。文字変数のアド
レスはわかっているのですが、終端文字に置換しようとすると、セグメ
ントエラーになってしまいます。これは如何にして解決すべきでしょう
か。よろしくお願いします。

Aベストアンサー

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが最大文字数に達したり、ファイルの最後になったりで、strに改行文字が含まれない場合には、このループは止まりません(Segmentension Falutになって止まる)

・そのような状態になってないか、予めチェックする
・ループを終了させる仕組みを用意しておく
: forの終了条件を記述する、for中で if(*(str+i)=='\0') { break;} 等としておく、等
といった対策が必要です。


あと細かいところを言えば
・strを配列で用意したなら *(s+i)じゃなくてs[i]でいいんじゃないかな
・あるいは char *pみたいにしておいて、 iのループでなく pでループを組む( for(p=str;*p!='\0';p++) )とか。

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが...続きを読む

QC言語での開発でエラーが出て困っています。

Eclipseを利用して初めてC言語で開発をしていますが、
エラーが発生していて困っています。
開発にはWindows7 の64ビット版を利用しています。
Program "g++" not found in PATH
Program "gcc" not found in PATH
Program "make" not found in PATH
の3種類が出ています。
初心者で申し訳ないです。
これらのエラーを解決する方法を教えてください。
宜しくお願いいたします。

Aベストアンサー

補足を読みました。
次はmakeですね。

 統合開発環境を起動してツールバーの中の「ウインドウ」→「設定」から「C/C++」をクリックし展開する。
 次に下の方の「新規 C/C++ プロジェクト・ウィザード」をクリック。

 中央のペインの「プロジェクトタイプ」で「実行可能」をクリックして展開。
 それぞれのプロジェクトが4種類現れるので、これをクリックし、右側のペインで適切なツールチェーンを選びます。
 今回は「LLVM with GCC(Windows)(MinGW)を示すようにクリックをしてください。
 この次に「優先ツールにする」を押下し、続けて「適用」ボタンを押下して設定を羽根井させてください。

 これでエラーは出なくなると思います。

Qprintfなど、標準関数のソースコードが知りたい

C言語、Linux初心者です。
タイトルの通り、printf, scanfなどの関数のソースコードや、main関数の呼出し部分のソースコードを見てみたいのですが、どこにあるのでしょうか。類似質問で
http://www.gnu.org/home.ja.html
から探せるとの回答がありましたが、出来ればもう少し具体的にお願いします。
RedHat Linux 7.3、gcc version 2.96を使っています。

Aベストアンサー

Linuxで用いられる「GNU Cライブラリ」(libc、glibc)はこちらです。http://www.gnu.org/software/libc/libc.html
http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/?cvsroot=glibc
例えばprintfは、この中の「stdio」という部分に含まれます。
http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/stdio/Attic/?cvsroot=glibc
リストの中の改訂番号(Rev.)をクリックすればソースが見られます。

mainの呼び出し部分については残念ながら詳しくありません。

参考URL:http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/stdio/Attic/?cvsroot=glibc

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);


人気Q&Aランキング