最近になって気付いたのですが…
同じ構造体ならば、a = bみたいに記述すればコピーできるんですねぇ…。試してないですが、クラスもいけるかもしれません。
ひょっとして、これってVCだけの仕様なんでしょうか?他の環境だと使えないのでしょうか?
なんにせよ、ずっとmemcpy関数を使ってたので、ちょっとだけ得した気分です(笑)
構造体のコピー
Re:構造体のコピー
Cの標準化がなされる前(K&R時代)までは、「=」で構造体のコピーはできませんでしたが
今のCでは、標準で使えると思ってまったく問題ないと思います。
標準化がなされる前は関数の引数とかも特別で
という記述方法がありました。
今のCではこの記述は使えませんけどね。
と、その時代を生きていないのに、勝手に語ってみました。
今のCでは、標準で使えると思ってまったく問題ないと思います。
標準化がなされる前は関数の引数とかも特別で
int main(argc, argv) int argc; char *argv[/url]; { reutrn 0; }
という記述方法がありました。
今のCではこの記述は使えませんけどね。
と、その時代を生きていないのに、勝手に語ってみました。
Re:構造体のコピー
>>試してないですが、クラスもいけるかもしれません。
基本的には(禁止指定されていなければ)クラスでも代入できますよ。
ただ、クラスの中身によっては妙なトラップに引っかかるので、注意が必要です。
>>memcpy関数を使ってたので
逆に C++だと memcpyを使う機会はぐっと減りますね。
PODタイプじゃないとクラスには使えませんから。
基本的には(禁止指定されていなければ)クラスでも代入できますよ。
ただ、クラスの中身によっては妙なトラップに引っかかるので、注意が必要です。
[color=#d0d0ff" face="monospace] class AAA
{
public:
AAA() : m_pValues(new int)
{ }
~AAA()
{ delete m_pValues;}
private:
int *m_pValues;
};
int main(void)
{
{
AAA a1;
AAA a2 = a1;
}
return 0;
}[/color]
これ実行すると a2への代入の後の }あたりで・・・。>>memcpy関数を使ってたので
逆に C++だと memcpyを使う機会はぐっと減りますね。
PODタイプじゃないとクラスには使えませんから。
Re:構造体のコピー
そういえば、少し前に仕事で、MS-Cで組まれたソフトの改造をしたのですが、そんな記述がされてました。
なんじゃこりゃ?
と思いましたが、納期が短かったので、そういう物なんだと無理矢理に納得して作業を進めましたが、そう書かなくてはいけなかったんですね。
謎が解けたのでスッキリしましたよ。ありがとうございました(^-^)
なんじゃこりゃ?
と思いましたが、納期が短かったので、そういう物なんだと無理矢理に納得して作業を進めましたが、そう書かなくてはいけなかったんですね。
謎が解けたのでスッキリしましたよ。ありがとうございました(^-^)
Re:構造体のコピー
でおくれましたが……
クラスの代入には、コピーコンストラクタというものが呼び出されます。
上のソースだと、
AAA::AAA(AAA&); // 同じクラスへの参照を引数にするコンストラクタ
という形のコンストラクタが呼び出されます。
これは、標準では、各メンバーをそのままコピーするような動作をします。
また、(クラスの代入を可能にするために)暗黙のうちに生成されてしまいます。
上記のような例だと、実際には、プライベートメンバーの差すものをもう一つ作って、そちらをポイントしたり、あるいは、同じ箇所をポイントしているという印をつけたりする必要がありますが、この場合、明示的に
AAA::AAA(AAA &);
を定義すればOKです。
また、そこまでしなくても、「間違って暗黙のうちに代入されてしまったら困る」場合には、
private:
AAA(AAA &);
で、代入はすべてエラーになります。
同じような「暗黙の代入」は、「他の型を単一の引数とするコンストラクタ」が定義されている時に発生します。
例えば、上記のソースで、
AAA::AAA(int); という形のコンストラクタがあると、
AAA a2;
a2 = 1;
などというのができてしまいます。
これを防止するためには、explicit をつけて、
explicit AAA::AAA(int) とすれば、
AAA a2(1); はOK
AAA a2 = 1; はエラー
になります。
クラスの代入には、コピーコンストラクタというものが呼び出されます。
上のソースだと、
AAA::AAA(AAA&); // 同じクラスへの参照を引数にするコンストラクタ
という形のコンストラクタが呼び出されます。
これは、標準では、各メンバーをそのままコピーするような動作をします。
また、(クラスの代入を可能にするために)暗黙のうちに生成されてしまいます。
上記のような例だと、実際には、プライベートメンバーの差すものをもう一つ作って、そちらをポイントしたり、あるいは、同じ箇所をポイントしているという印をつけたりする必要がありますが、この場合、明示的に
AAA::AAA(AAA &);
を定義すればOKです。
また、そこまでしなくても、「間違って暗黙のうちに代入されてしまったら困る」場合には、
private:
AAA(AAA &);
で、代入はすべてエラーになります。
同じような「暗黙の代入」は、「他の型を単一の引数とするコンストラクタ」が定義されている時に発生します。
例えば、上記のソースで、
AAA::AAA(int); という形のコンストラクタがあると、
AAA a2;
a2 = 1;
などというのができてしまいます。
これを防止するためには、explicit をつけて、
explicit AAA::AAA(int) とすれば、
AAA a2(1); はOK
AAA a2 = 1; はエラー
になります。
for文の不思議
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #define Correct 1 #define Error 0 enum eScale { binary, octal, hexadecimal, decimal, } scale_pat; void input_scale(int scale_pat); //基数変換をする関数. void f_binary(char value[/url], int b_null); void f_octal(char value[/url], int b_null); void f_hexadecimal(char value[/url], int b_null); void f_decimal(char value[/url]); int main (void){ int cnt, check, e; char msg[10]; printf("Please choose the following\n\n"); printf("binary scale : 1\noctal scale : 2\nhexadecimal scale : 3\ndecimal scale : 4\n\n"); printf("Please input >>>"); do{ scanf(" %d", &cnt); e = getchar(); switch(cnt){ case 1: input_scale(binary); check = Correct; break; case 2: input_scale(octal); check = Correct; break; case 3: input_scale(hexadecimal); check = Correct; break; case 4: input_scale(decimal); check = Correct; break; default : printf("*Error*\n"); printf("Please input different value >>>"); check = Error; break; } }while(check == Error); return 0; } void input_scale(const int scale_pat){ int a, cnt, check; char scale[10]; printf("Please input the number >>>"); fgets(scale, sizeof(scale), stdin); switch(scale_pat){ case binary: //構文チェックを行う. for(cnt = 0, check = 0; scale[cnt] != '\n'; cnt++){ if(scale[cnt] == '0' || scale[cnt] == '1') check++; } if(check == cnt) f_binary(scale, check - 1);//2進数からの他の進数に変換する関数を呼ぶ. else{ fprintf(stderr, "*Error*\n");//エラー時に強制終了する. exit(EXIT_FAILURE); } break; case octal: //構文チェックを行う. if(scale[0] != '0'){ printf("*Error*\n"); exit(EXIT_FAILURE); } for(cnt = 0, check = 0; scale[cnt] != '\n'; cnt++){ if(scale[cnt] != '8' && scale[cnt] != '9') check++; } if(check == cnt) f_octal(scale, check - 1);//2進数からの他の進数に変換する関数を呼ぶ. else{ fprintf(stderr, "*Error*\n");//エラー時に強制終了する. exit(EXIT_FAILURE); } break; case hexadecimal: //構文チェックを行う. if(scale[0] != '0' || scale[1] != 'x'){ fprintf(stderr, "*Error*\n");//エラー時に強制終了する. exit(EXIT_FAILURE); } for(cnt = 2, check = 2; scale[cnt] != '\n'; cnt++){ if(isxdigit(scale[cnt])) check++; } if(check == cnt) f_hexadecimal(scale, check - 1);//10進数からの他の進数に変換する関数を呼ぶ. else{ fprintf(stderr, "*Error*\n");//エラー時に強制終了する. exit(EXIT_FAILURE); } break; case decimal: //構文チェックを行う. for(cnt = 0, check = 0; scale[cnt] != '\n'; cnt++){ if(isdigit(scale[cnt])) check++; } if(check == cnt) f_decimal(scale);//10進数からの他の進数に変換する関数を呼ぶ. else{ fprintf(stderr, "*Error*\n");//エラー時に強制終了する. exit(EXIT_FAILURE); } break; } return; } void f_binary(char value[/url], int b_null){ int cnt; for(cnt = 0; value[cnt] != '\0'; cnt++){ } } void f_octal(char value[/url], int b_null){ int cnt; for(cnt = 0; value[cnt] != '\0'; cnt++){ } } void f_hexadecimal(char value[/url], int b_null){ int cnt; for(cnt = 0; value[cnt] != '\0'; cnt++){ } } void f_decimal(char value[/url]){ int decimal, cnt = 0, a_dec[100]; decimal = atoi(value); //2進数に変換. for(cnt = 0; decimal != 0; cnt++){ a_dec[cnt] = decimal % 2;//余り decimal /= 2; } for(cnt -= 1; cnt >= 0; cnt--){ printf("%d", a_dec[cnt]); } printf("(2)\n"); //8進数に変換. for(cnt = 0; decimal != 0; cnt++){ a_dec[cnt] = decimal % 8;//余り decimal /= 8; } for(cnt -= 1; cnt >= 0; cnt--){ printf("%d", a_dec[cnt]); } printf("(8)\n"); //16進数に変換. for(cnt = 0; decimal != 0; cnt++){ a_dec[cnt] = decimal % 16;//余り decimal /= 16; } for(cnt -= 1; cnt >= 0; cnt--){ switch(a_dec[cnt]){ case 10: printf("A"); break; case 11: printf("B"); break; case 12: printf("C"); break; case 13: printf("D"); break; case 14: printf("E"); break; case 15: printf("F"); break; default : printf("%d", a_dec[cnt]); break; } } printf("(16)\n"); return; }昨日質問したものとちょっと違うので新しくトピを立てさせていただきます。
f_decimal関数内の2進数に変換するfor文はちゃんと動いてくれるのですがそれ以降の8進数・16進数のところはまるでコメントアウトしているように振舞われるのです。(まるでなかったように)
原因を教えて頂けませんか?
環境はCygwinです。
Re:for文の不思議
f_binary / f_octal/ f_hexadecimal関数ですか?
きっと何もしてないので、コンパイラによって削除されてしまったんでしょう。
"int cnt"を "volatile int cnt"とすると消されずに済むかもしれませんよ。
きっと何もしてないので、コンパイラによって削除されてしまったんでしょう。
"int cnt"を "volatile int cnt"とすると消されずに済むかもしれませんよ。
Re:for文の不思議
2進数への変換が終わったとき、decimalの値はゼロになっています。
したがって、8進数や16進数への変換を行なうためのループを、
一度も実行しません。
したがって、8進数や16進数への変換を行なうためのループを、
一度も実行しません。
Re:for文の不思議
失礼しました。
f_decimalの中の8進数・16進数の処理ですね。
ただ単に for文の中の条件式にマッチしなかったからじゃないでしょうか。
f_decimal関数の先頭で atoiで変数 decimalに値を設定していますが、
直後の2進数変換の中で decimal値が0に変化してしまっています。
その変化した decimal値をもって8・16進数に変換しようとしているので、
for文の条件に失敗していると思われます。
f_decimalの中の8進数・16進数の処理ですね。
ただ単に for文の中の条件式にマッチしなかったからじゃないでしょうか。
f_decimal関数の先頭で atoiで変数 decimalに値を設定していますが、
直後の2進数変換の中で decimal値が0に変化してしまっています。
その変化した decimal値をもって8・16進数に変換しようとしているので、
for文の条件に失敗していると思われます。