简体   繁体   English

从字符串构建函数打印输出未返回预期结果

[英]Printing output from string building function not returning expected result

I'm writing a function to output a basic hours & minutes string in 24 hour format from two global int's containing hours and minutes. 我正在编写一个函数,以从两个包含小时和分钟的全局整数输出24小时格式的基本小时和分钟字符串。

I've defined these during initialization: 我在初始化期间定义了这些:

int g_alarmHours = 7;
int g_alarmMinutes = 0;

The function to return the string is: 返回字符串的函数是:

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;
}

The global variables are stubs to be replaced when serial comms to another device are added where those values will be retrieved from. 全局变量是在将串行通信添加到另一台设备(从中检索这些值)时要替换的存根。

Calling the function generates the following hex values at the character pointer: 调用该函数会在字符指针处生成以下十六进制值:

0x20 0x4b 0x00

When I replace the top two lines of the getAlarmTime() function with the following 当我将getAlarmTime()函数的前两行替换为以下内容时

int hours = 7;
int minutes = 0;

The output is then what I expect, of: 然后输出是我期望的:

07:00\0

Why is using those global variables causing the output of getAlarmTime() to go so wonky? 为什么使用这些全局变量导致getAlarmTime()的输出变得如此奇怪?

You are returning a pointer to a local variable on the stack. 您正在返回一个指向堆栈上的局部变量的指针。 The memory the pointer is pointing at is no longer valid and accessing that memory invokes undefined behavior. 指针指向的内存不再有效,访问该内存将调用未定义的行为。 The reason why you are seeing such strange behavior is because anything can happen when you invoke undefined behavior. 之所以看到这种奇怪的行为,是因为调用未定义的行为会发生任何事情。

The solution to your problem would be to code in C++ and use std::string. 解决您的问题的方法是使用C ++编写代码并使用std :: string。

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

return t;

You are returning a pointer to an array that is local to your function only. 您将返回一个指向仅在函数本地的数组的指针。 Thus when your function exits the array that was created in your function no longer exists and any attempt to access that memory will result in undefined behaviour. 因此,当函数退出时,在函数中创建的数组将不再存在,并且任何访问该内存的尝试都将导致未定义的行为。

Why is using those global variables causing the output of getAlarmTime() to go so wonky? 为什么使用这些全局变量导致getAlarmTime()的输出变得如此奇怪?

You are actually looking at undefined behavior here, because you are returning the address of a local (stack) variable. 实际上,您正在查看未定义的行为,因为您正在返回本地(堆栈)变量的地址。

The following sequence takes place: 发生以下顺序:

  • You call getAlarmTime . 您调用getAlarmTime

  • compiler allocates stack space for it's variables (hours, minutes and t). 编译器为其变量(小时,分钟和t)分配堆栈空间。

  • Then t is filled 然后t被填充

  • you return t's address. 您返回t的地址。

  • control exits function and the address you returned points to unused stack space. 控件退出函数,并且您返回的地址指向未使用的堆栈空间。

Subsequent stack data (variables declared afterwards or other function calls) will overwrite this space. 随后的堆栈数据(此后声明的变量或其他函数调用)将覆盖此空间。

Solution: Consider returning a std::string instead of a char* . 解决方案:考虑返回std::string而不是char*

You are returning a Local variable as pointer. 您将返回一个Local变量作为指针。

return t;

The Ideone compiler returned the following error while compiling: Ideone编译器在编译时返回以下错误:

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

But i don't understand how it works when you replace the 1st 2 lines with 但是我不明白当您用1替换第2行时它是如何工作的

int hours = 7;
int minutes = 0;

Use string or pass by deference to solve your issue. 使用字符串或通过引用来解决您的问题。 Or even a Global variable can solve your issue. 甚至全局变量也可以解决您的问题。

You're returning a pointer to a local array. 您正在返回一个指向本地数组的指针。 It is destroyed before the caller can access it, giving undefined behaviour; 它会在调用者访问之前被销毁,从而产生不确定的行为。 in practice it may or may not be overwritten with someone else's data. 实际上,它可能会或可能不会被其他人的数据覆盖。

The usual solution would be to return a dynamic array (such as std::string ); 通常的解决方案是返回一个动态数组(例如std::string ); but since you say you have extreme memory restrictions that would be a bad idea here. 但是,既然您说您有极端的内存限制,那么在这里就不好了。

I would modify the function so that the caller supplies the buffer: 我将修改该函数,以便调用方提供缓冲区:

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;
}

Beware that the caller is now responsible for making sure the buffer is large enough. 注意,调用者现在负责确保缓冲区足够大。 Even though I declared the parameter as char[6] , that serves only as documentation; 即使我将参数声明为char[6] ,也仅用作文档; to the compiler it's the same as char* . 对于编译器,它与char*相同。

Another possibility is to make the local buffer static; 另一种可能性是使本地缓冲区静态。 but beware that the function will no longer be reentrant or thread-safe, which could lead to weird bugs. 但请注意,该函数将不再是可重入的或线程安全的,这可能会导致奇怪的错误。

Why is using those global variables causing the output of getAlarmTime() to go so wonky? 为什么使用这些全局变量导致getAlarmTime()的输出变得如此奇怪?

My guess would be that, when you initialise the local variables with constants, the compiler eliminates them and uses the constants instead. 我的猜测是,当用常量初始化局部变量时,编译器会消除它们,而改用常量。 This moves the array to somewhere else in the stack, where it happens not to be overwritten before you examine it. 这会将数组移到堆栈中的其他位置,在您检查之前,它恰好不会被覆盖。 But this is all in the realms of undefined behaviour, so the exact details aren't of any practical interest. 但这都是不确定行为的领域,因此确切的细节没有任何实际意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM