0

我正在编写一个函数,以从两个包含小时和分钟的全局 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;
}

全局变量是在添加到另一个设备的串行通信时要替换的存根,这些值将从中检索。

调用该函数会在字符指针处生成以下十六进制值:

0x20 0x4b 0x00

当我用getAlarmTime()以下内容替换函数的前两行时

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的地址。

  • 控制退出函数并且您返回的地址指向未使用的堆栈空间。

随后的堆栈数据(之后声明的变量或其他函数调用)将覆盖此空间。

解决方案:考虑返回 astd::string而不是 a char*

于 2013-08-28T11:14:16.960 回答
0

您正在返回一个局部变量作为指针。

return t;

Ideone 编译器在编译时返回以下错误:

prog.cpp:在函数'char * getAlarmTime()'中:prog.cpp:8:8:警告:返回局部变量't'的地址[-Wreturn-local-addr] char t [6];

但是我不明白当你用 1st 2 替换它时它是如何工作的

int hours = 7;
int minutes = 0;

使用字符串或顺从来解决您的问题。甚至全局变量也可以解决您的问题。

于 2013-08-28T11:17:26.283 回答
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*.

另一种可能性是使本地缓冲区静态;但请注意,该函数将不再是可重入的或线程安全的,这可能会导致奇怪的错误。

为什么使用这些全局变量会导致 getAlarmTime() 的输出如此不稳定?

我的猜测是,当您使用常量初始化局部变量时,编译器会消除它们并改用常量。这会将数组移动到堆栈中的其他位置,在您检查它之前它恰好不会被覆盖。但这都属于未定义行为的领域,因此确切的细节没有任何实际意义。

于 2013-08-28T11:25:54.863 回答