【復活求む!】惜しくも解散してしまったバンド|J-ROCK編 >>

c言語にsprintf関数っていうのがありますが、
これはどうやって作るのでしょうか?

sprintf関数は引数の数が可変であり、引数のデータ型
が様々なので、いったいどうやって作るのか知りたいです。

どこかにソースでもあればいいのですが・・・。

A 回答 (4件)

#2です。


回答したもののそれほど詳しくはないのですが…。

(1) 引数の個数はどうやって知るのか?

知ることはできません。
従って受け取り側で決め打ちしてやることになりますね。
printfを例に取れば、例えば "%d%d%d" とあれば3つ引数がある“はず”として処理する。
実際にprintfで "%d%d%d" に対して1つしか引数を与えなくてもエラーにはなりません。その代わり無理やり処理して変な値が出ますよね。

(2) 引数の型はどうやって知るのか?

これまた知ることはできません。
従ってこれまた受け取り側で決め打ちにすることになります。
ただprintfの場合ですと書式内に型が明示されているので、%dだからint型で受け取ろうとか、%sならchar*型で受け取ろうと処理できます。
    • good
    • 1
この回答へのお礼

なるほど!
今作ろうとしている関数は自作のsprintf関数
なんです。

sprintf(str, "a = %d, b = %d\n", data1, data2);

などとしたいのですね。ご指摘のとおり書式文字列
の中を調べて引数の数を推測することができますね。
なるほど。

すっきりしました。ありがとう。

お礼日時:2006/05/08 17:50

> どこかにソースでもあればいいのですが・・・。



簡単なので、ここに書きます。

#include <stdio.h>
#include <stdarg.h>

int sprintf(char *s, const char *format, ...)
{
 va_list ap;
 int result;

 va_start(ap, format);
 result = vsprintf(s, format, ap);
 va_end(ap);
 return result;
}
    • good
    • 1

可変引数のプロトタイプは次のような感じで宣言します。



void func(int num, ...)

また可変引数は、va_start(),va_arg(),va_end()という関数で処理できます。

詳しくはこちらのページを参照。
http://www.geocities.jp/ky_webid/c/057.html

この回答への補足

すばやいアドバイスありがとう。

少し質問させてください。

(1) 引数の個数はどうやって知るのか?
(2) 引数の型はどうやって知るのか?

とても気になります。

補足日時:2006/05/08 16:56
    • good
    • 0
    • good
    • 0

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

このQ&Aを見た人はこんなQ&Aも見ています

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

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

Qsprintfのような関数を自作する

表題のようにsprintfのような関数を自作することはできますか?

行いたいのは、例えば、

void TestKansu(AnsiString str)
{
//str文字列を処理
}

という関数を用意したとしてこれを使うには

AnsiString str;
str.sprintf("TestMessage %d" , tes);
TestKansu(str);

としなくてはいけないと思いますが、もっと簡潔に

TestKansu("TestMessage %d" , tes);

とできるような関数を自作することは可能ですか?

C++です。

宜しくお願いいたします。

Aベストアンサー

本家sprintfはC言語で書かれているわけですから、当然自分で作ることが出来ます。

「Programming Place Plus C言語編 第52章 可変個引数」
http://www.geocities.jp/ky_webid/ProgrammingPlacePlus/c/052.html

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

Qsprintf関数での文字列変換について

マイコンにて、
C言語で浮動小数点の数値を表示するプログラムを作成しているのですが、

PRINT_OUT("123.456");
のように、文字列を直接指定した場合は正しく表示されるのですが、

sprintf()関数を用いて、浮動小数点を文字列に変換した場合、
buf char[10];
sprintf(buf,"%lf",123.456);
PRINT_OUT(buf);
とした場合はプログラムが暴走?(恐らく配列破壊を起こしていると
思われますが、)してしまい、上手く動作しません。
(但し、整数の場合は正常に動作します。)

そこで、質問させていただきたいのですが、
"123.456"のように直接文字列を指定した場合と、浮動小数点123.456
をsprintf()関数を用いて文字列に変換した"123.456"の書式に何か
違いはあるのでしょうか?よろしくお願い致します。

Aベストアンサー

> sprintf(buf,"%lf",123.456);

まず、double型の書式指定は %lf ではなく %f です。
%lf を使った場合の動作は未定義ですので、何が起こっても不思議ではありません(C99対応の場合はOKです)。

また、PRINT_OUT関数の仕様が不明ですので、もしかするとそこに原因があるのかもしれません。

参考URL:http://www.kijineko.co.jp/tech/superstitions/printf-format-for-double

Qint型からchar型への変換

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

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

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

Qファイルやディレクトリの存在確認を行う方法

ファイルをオープンするのはfopenでOKですが、ファイルやディレクトリの存在確認を行う方法が知りたいです。

何か組み合わせて作るものなのでしょうか?
perlとか便利な演算子があるのですが、C/C++って器用ではないですね。
これは処理系?依存の内容ですか?

私の環境は VC6, VC2005 Windows2000です。

Aベストアンサー

int access(const char* path, int mode);
int stat(const char* path, struct stat* sb);

かな?
MSDN を引くと _access_s() を使えとか書いてあるけど。

Qitoaわかりません

c言語で、itoaの関数を使いたいのですが、stdlib.hに設定されてなく、エラーが、'_itoa' value is undefinedと出ます。どうしたら、itoaが使えるようになりますか?]

Aベストアンサー

★『OAKS16MINI』って組み込み系?
・sprintf 関数はありますか?
 この関数もない場合は itoa() 関数を自前で用意することになります。
 下に簡単なサンプルを載せておきます。

サンプル:
char *itoa( int value, char buff[], int radix )
{
 static const char table[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 char *head = buff;
 char *tail = buff;
 char temp;
 
 // マイナス符号を文字列に変換
 if ( value < 0 ){
  *tail++ = '-';
  value = -value;
 }
 // 整数値を文字列に変換
 if ( value == 0 ){
  *tail++ = '0';
 }
 else for ( head = tail ; value != 0 ; value /= radix ){
  *tail++ = table[ value % radix ];
 }
 *tail = '\0';
 // 文字列の左右入れ替え
 for ( tail-- ; head < tail ; head++, tail-- ){
  temp = *head;
  *head = *tail;
  *tail = temp;
 }
 return buff;
}

以上。

★『OAKS16MINI』って組み込み系?
・sprintf 関数はありますか?
 この関数もない場合は itoa() 関数を自前で用意することになります。
 下に簡単なサンプルを載せておきます。

サンプル:
char *itoa( int value, char buff[], int radix )
{
 static const char table[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 char *head = buff;
 char *tail = buff;
 char temp;
 
 // マイナス符号を文字列に変換
 if ( value < 0 ){
  *tail++ = '-';
  value = -value;
 }
 // 整...続きを読む

QLNK2019: 未解決の外部シンボルのエラーが出る

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自キャラのデータ
Point2D g_jikipos = {40, 400};//自キャラの座標

//画像ハンドル
int g_jikiimage[11];

//色々なファイルの読み込み
int LoadFiles(){
//画像ファイル読み込み
if(LoadDivGraph("media\\player01.bmp",
11,11,1,64,64,g_jikiimage) == -1) return -1;

return 1;
}


 mymain.h
//他から呼び出させるMyMainの関数
void MyMain();
int LoadFiles();


 myhelper.h(サンプルなので打ちミスはない)
#include "DxLib.h"
#include <limits.h>
#include <math.h>

//構造体宣言
//座標またはベクトルを記録する構造体
struct Vector{
float x,y;
};
typedef Vector Point2D;
//線を記録する構造体
struct Line2D{
Point2D startpos, endpos;
float katamuki;//傾きをラジアン値で記録
Vector speed;//移動している場合は速度をセット
};
//球体を記録する構造体
struct Ball2D{
Point2D position;
float hankei;//半径
};
//四角形を記録する構造体
struct Rect2D{
Point2D lefttop;
Point2D rightbottom;
float width;
float height;
};


//ライブラリ関数
Point2D PosInView(Point2D in);
int XInView(float inx);
int YInView(float iny);
void ScrollToLeft(float jikiposx);
void ScrollToRight(float jikiposx);
void ScrollToUp(float jikiposy);
void ScrollToDown(float jikiposy);
void DrawLineInView(float x1, float y1, float x2, float y2, int Color, int Thickness);
void DrawCircleInView(float x, float y, float r, int Color, int FillFlag);
void DrawAnimation(float x, float y, double ExtRate, double Angle,int TurnFlag,
int *imgarray, int allframe, float fps);
//ベクトル関数
Vector CreateVector(Vector in, float veclen);
Vector AddVector(Vector v1, Vector v2);
Vector SubVector(Vector v1, Vector v2);
Vector AddVectorInFrameTime(Vector pos, Vector speed);
Vector AddVectorInFrameTime2(Vector pos, Vector speed, Vector accel);
Vector Normalize(Vector in);
Vector RotateVector(Vector in, float radian);
float VectorLengthSquare(Vector in);
float DotProduct(Vector v1, Vector v2);
float CrossProduct(Vector v1, Vector v2);
void SetLine2DKatamuki(Line2D *in);
void DrawLine2D(Line2D in, int Color, int Thickness);
void DrawBall2D(Ball2D in, int Color, int Fill);
//当たり判定関数
bool HitTestLineAndBall(Line2D linein, Ball2D ballin);
bool IsPointAtLineFace(Line2D linein, Point2D ptin);
bool HitTestLineAndLine(Line2D line1, Line2D line2);
bool HitTestBallAndBall(Ball2D a, Ball2D b);
bool HitTestPointAndBox(Rect2D rect, Point2D pt);
//タイマー関数
void SetSimpleTimer(int idx, int time);
int GetPassedTime(int idx);


//グローバル変数
extern float g_frametime;
extern Rect2D g_framerect;//画面領域(当たり判定)
extern Point2D g_current_field_pos;//現在の左上座標
extern Rect2D g_stagesize;//ステージサイズ

//定数宣言
const float ZEROVALUE = 1e-10f;
const float PIE = 3.1415926f;
const int SCROLL_LIMIT = 200;
----------------------------------------------------------------
 エラー内容
1>myhelper.obj : error LNK2019: 未解決の外部シンボル "void __cdecl MyMain(void)" (?MyMain@@YAXXZ) が関数 _WinMain@16 で参照されました
1>C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\my\Debug\my.exe : fatal error LNK1120: 外部参照 1 が未解決です
1>my - エラー 2、警告 0
ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ
----------------------------------------------------------------
画像を貼り付けときます
(見えにくい場合→http://www.dotup.org/uploda/www.dotup.org154142.jpg.html)
初心者なのでわかりやすくお願いします

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自...続きを読む

Aベストアンサー

ファイル構成から推測するに
mymain.cpp というファイルに
void MyMain(void) {
// ここに処理を書く
}
という関数が必要なようです。

QC言語で、数値の桁数を求めるには??

C言語で数値の桁数を求めるプログラムをもとめたいのですが
どうすればいいのでしょうか
int c;
int a;
c=12345;
a=printf("%d",c);

とするとaに桁数は入るのですが
cがPRINTF関数により表示されてしまいます

どうすればいいでしょうか?
わかる方はおしえてください、おねがいします。

Aベストアンサー

 sprintf 関数というのがあります。
 printf 関数とまったく同じですが、結果を変数に出力する点が違います。

 char dummy[10];
 int c, a;
 c=12345;
 a=printf(dummy, "%d",c);

 この dummy 変数には文字列 "12345" が入りますが、使わなければどうということはないです。

 C言語を使い始めてそろそろ10年になりますが、sprintf をこんなふうに使おうとは思いもしませんでした(^_^;
 なんか反則っぽいですけど、合理的ですね(笑)

 ちなみに、答えが0になるまで10で割っていって、割ることができた回数を数えるのが普通のやりかたです。

Q「memcpy」と「strcpy」について

C言語の初心者です。
先日、課題として以下のようなことを言われました。

「memcpyとstrcpyについて、メモリ破壊が起こるとしたら
どんな場合が考えられるか、簡単にまとめて報告してみて下さい。」
と言われました。

私にはメモリ破壊というニュアンスが分からないのですが、
どちらの関数も必要以上にコピーを行ったときに
起こるメモリ破壊ということなのでしょうか?
それとも、何か特別な意味があるのでしょうか?

C言語に詳しい方がいましたら、是非、教えて下さい。
宜しくお願いします。

Aベストアンサー

 メモリ破壊とは、「当然そこに入っているべき値」を、不用意に上書きしてしまうことです。

 たとえば、char a[100]; という宣言をしたとします。

 memcpy( a, 0, 200 );

 すると、このような実行を行った場合、変数 a の後ろにどんなメモリが存在しているのかプログラマは知ることができないのに、変数 a の後ろの未定メモリ100バイトを上書きしてしまいます。

 この未定メモリには、もしかしたら別の変数があるかもしれませんし、プログラムの一部があるかもしれません。あるいはOSのシステム領域かもしれません。
 どのみちプログラムは正常に動かなくなります。
 通常はメモリエラーが出て停止しますが、最悪の場合、メモリ上のOSを破壊してリセットするしかなくなったりもします。

 これがメモリ破壊です。

Qprintfのコードは?

C言語において、
printf等の標準関数もC言語で書かれていると聞きましたが、そのコードそのものを見ることが出来るのでしょうか?

ご存知の方、よろしくお願いいたします。

Aベストアンサー

平林雅英(著) 新ANSI C言語辞典/技術評論社(刊)
に定義例として載っています。それによると、

#include <stdio.h> /* vfprintf */
#include <stdarg.h> /* va_list, va_start, va_end */
int printf(const char *format, ...)
{
int r;

va_list args; /* 作業用変数の定義 */
va_start(args, format); /* 初期化 */
r=vfprintf(stdout, format, args);
va_end(args); /* 終了 */
return r;
}

・・・てな具合です。
この辞典には他にも様々な標準関数の定義例が載っていますので勉強になります。もちろんこれはprintf関数の実装の一例ですからmk1234さんの持っているコンパイラのソースコードがこのようになっているとは限りません。


人気Q&Aランキング