0

時間と分を含む 2 つのグローバル int から基本的な時間と分の文字列を 24 時間形式で出力する関数を作成しています。

初期化中にこれらを定義しました:

int g_alarmHours = 7;
int g_alarmMinutes = 0;

文字列を返す関数は次のとおりです。

char* getAlarmTime() {
  int hours = g_alarmHours;
  int minutes = g_alarmMinutes;
  char t[6];
  t[0] = (hours/10) + '0';
  t[1] = (hours%10) + '0';
  t[2] = ':';
  t[3] = (minutes/10) + '0';
  t[4] = (minutes%10) + '0';
  t[5] = 0;
  return t;
}

グローバル変数は、それらの値が取得される別のデバイスへのシリアル通信が追加されたときに置き換えられるスタブです。

関数を呼び出すと、文字ポインターに次の 16 進値が生成されます。

0x20 0x4b 0x00

getAlarmTime()関数の最初の 2 行を次のように置き換えると、

int hours = 7;
int minutes = 0;

出力は、私が期待するものです。

07:00\0

これらのグローバル変数を使用すると、出力が不安定になるのはgetAlarmTime()なぜですか?

4

5 に答える 5

4

スタック上のローカル変数へのポインターを返しています。ポインタが指しているメモリは無効になり、そのメモリにアクセスすると未定義の動作が発生します。このような奇妙な動作が見られるのは、未定義の動作を呼び出すと何かが発生する可能性があるためです。

問題の解決策は、C++ でコーディングして std::string を使用することです。

std::string t;
t.push_back((hours/10) + '0');
...

return t;
于 2013-08-28T11:13:34.337 に答える
2

関数のみにローカルな配列へのポインターを返しています。したがって、関数が終了すると、関数で作成された配列は存在しなくなり、そのメモリにアクセスしようとすると、未定義の動作が発生します。

于 2013-08-28T11:13:44.510 に答える
1

これらのグローバル変数を使用すると、getAlarmTime() の出力が不安定になるのはなぜですか?

ローカル (スタック) 変数のアドレスを返しているため、実際にはここで未定義の動作を見ています。

次のシーケンスが行われます。

  • を呼び出しますgetAlarmTime

  • コンパイラは、その変数 (時間、分、および t) にスタック スペースを割り当てます。

  • 次に、tが満たされます

  • t のアドレスを返します。

  • 制御は関数を終了し、返されたアドレスは未使用のスタック領域を指しています。

後続のスタック データ (後で宣言された変数または他の関数呼び出し) は、このスペースを上書きします。

解決策:std::stringの代わりにを返すことを検討してくださいchar*

于 2013-08-28T11:14:16.960 に答える
0

ローカル配列へのポインターを返しています。呼び出し元がアクセスする前に破棄され、未定義の動作が発生します。実際には、他の誰かのデータで上書きされる場合とされない場合があります。

通常の解決策は、動的配列 ( などstd::string) を返すことです。しかし、極端なメモリ制限があると言うので、ここでは悪い考えです。

呼び出し元がバッファーを提供するように関数を変更します。

void getAlarmTime(char t[6]) {
  int hours = g_alarmHours;
  int minutes = g_alarmMinutes;
  t[0] = (hours/10) + '0';
  t[1] = (hours%10) + '0';
  t[2] = ':';
  t[3] = (minutes/10) + '0';
  t[4] = (minutes%10) + '0';
  t[5] = 0;
}

バッファーが十分な大きさであることを確認する責任が呼び出し元にあることに注意してください。パラメータを として宣言しましたがchar[6]、これはドキュメントとしてのみ機能します。コンパイラにとっては と同じchar*です。

もう 1 つの可能性は、ローカル バッファーを静的にすることです。ただし、関数が再入可能またはスレッドセーフではなくなることに注意してください。これにより、奇妙なバグが発生する可能性があります。

これらのグローバル変数を使用すると、getAlarmTime() の出力が不安定になるのはなぜですか?

私の推測では、ローカル変数を定数で初期化すると、コンパイラはそれらを削除し、代わりに定数を使用します。これにより、配列がスタック内の別の場所に移動されます。そこでは、調べる前に上書きされません。しかし、これはすべて未定義の動作の領域にあるため、正確な詳細は実際には重要ではありません。

于 2013-08-28T11:25:54.863 に答える
0

ローカル変数をポインターとして返しています。

return t;

Ideone コンパイラは、コンパイル中に次のエラーを返しました:

prog.cpp: 関数 'char* getAlarmTime()' 内: prog.cpp:8:8: 警告: ローカル変数 't' のアドレスが返されました [-Wreturn-local-addr] char t[6];

しかし、最初の2行を次のように置き換えると、どのように機能するのかわかりません

int hours = 7;
int minutes = 0;

問題を解決するには、文字列を使用するか、順守して渡します。または、グローバル変数でも問題を解決できます。

于 2013-08-28T11:17:26.283 に答える