制作 os 时按引用传递错误
Error passing by reference when making os
我正在制作一个 os 并且已经启动到一个用 c 制作的 64 位内核。我已经制作了一个正在运行的打印函数,并且正在尝试制作一个将十六进制值转换为字符串的函数,以便我可以打印它们。我的代码导致引导循环,但是当我在 linux 中正常将完全相同的代码编译为 运行 时,它运行良好。相关代码:
int logarithm(double value, int base, int* output) {
int i = 0;
while (value > 1) {
value /= base;
i++;
}
*output = i;
}
int power(int value, int power, int* output) {
if (power == 0) {
value = 1;
} else {
for (int i = 0; i < (power - 1); i++) {
value *= value;
}
}
*output = value;
}
void hexToStr(unsigned int hex, char** string) {
int hexLength = 0;
logarithm((double)hex, 16, &hexLength);
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
power(16, i, &powerValue);
output[hexLength - i - 1] = (hex & (powerValue * 15)) / powerValue + '0';
}
*string = output;
}
如果我将 hexToStr() 函数代码更改为此(通过对字符串的硬编码值消除对 logarithm() 和 power() 函数的需要),它在 linux 和我的内核中都有效:
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
关于为什么会发生这种情况有什么建议吗?
提供的代码调用了未定义的行为。例如让我们考虑这个函数
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
在这个赋值语句中:
output[hexLength] = 0;
由于索引的有效范围为[0, hexLength)
.
,数组外有写入数据
或者函数通过引用局部数组output
设置一个传递给函数的指针,退出函数后不会存活。因此 returned 指针将具有无效值。
另一个例子当参数value
等于3
且参数power
等于3
时函数power
的结果值由于此 for 循环中的赋值语句,将等于 81
而不是 27
。
for (int i = 0; i < (power - 1); i++) {
value *= value;
}
此外,函数 return 什么都没有,尽管它的 return 类型不是 void。
int power(int value, int power, int* output) {
还有这个表情
(hex & (powerValue * 15)) / powerValue + '0'
没有意义。
需要启用 SSE 单元才能使用浮点数和双精度数。以及更改值的传回方式。工作代码:
void log(float value, float base, uint64_t* output) {
uint64_t i = 0;
while (value >= 1) {
value /= base;
i++;
}
*output = i;
}
void pow(uint64_t value, uint64_t exponent, uint64_t* output) {
uint64_t result = 1;
for (uint64_t i = 0; i < exponent; i++) {
result = result * value;
}
*output = result;
}
void hexToStr(uint64_t hex, char* output) {
uint8_t hexLen = 16;
log((float)hex, (float)16, &hexLen);
char result[hexLen + 3];
result[0] = '0';
result[1] = 'x';
result[hexLen + 2] = 0;
uint64_t powerValue = 1;
for (uint8_t i = 0; i < hexLen; i++) {
pow(16, i, &powerValue);
result[hexLen - i + 1] = (hex & (uint64_t)(powerValue * (uint64_t)15)) / powerValue + '0';
}
for (uint8_t i = 0; i < hexLen + 3; i++) {
switch(result[i]) {
case ':':
result[i] = 'A';
break;
case ';':
result[i] = 'B';
break;
case '<':
result[i] = 'C';
break;
case '=':
result[i] = 'D';
break;
case '>':
result[i] = 'E';
break;
case '?':
result[i] = 'F';
break;
}
output[i] = result[i];
}
}
我正在制作一个 os 并且已经启动到一个用 c 制作的 64 位内核。我已经制作了一个正在运行的打印函数,并且正在尝试制作一个将十六进制值转换为字符串的函数,以便我可以打印它们。我的代码导致引导循环,但是当我在 linux 中正常将完全相同的代码编译为 运行 时,它运行良好。相关代码:
int logarithm(double value, int base, int* output) {
int i = 0;
while (value > 1) {
value /= base;
i++;
}
*output = i;
}
int power(int value, int power, int* output) {
if (power == 0) {
value = 1;
} else {
for (int i = 0; i < (power - 1); i++) {
value *= value;
}
}
*output = value;
}
void hexToStr(unsigned int hex, char** string) {
int hexLength = 0;
logarithm((double)hex, 16, &hexLength);
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
power(16, i, &powerValue);
output[hexLength - i - 1] = (hex & (powerValue * 15)) / powerValue + '0';
}
*string = output;
}
如果我将 hexToStr() 函数代码更改为此(通过对字符串的硬编码值消除对 logarithm() 和 power() 函数的需要),它在 linux 和我的内核中都有效:
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
关于为什么会发生这种情况有什么建议吗?
提供的代码调用了未定义的行为。例如让我们考虑这个函数
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
在这个赋值语句中:
output[hexLength] = 0;
由于索引的有效范围为[0, hexLength)
.
或者函数通过引用局部数组output
设置一个传递给函数的指针,退出函数后不会存活。因此 returned 指针将具有无效值。
另一个例子当参数value
等于3
且参数power
等于3
时函数power
的结果值由于此 for 循环中的赋值语句,将等于 81
而不是 27
。
for (int i = 0; i < (power - 1); i++) {
value *= value;
}
此外,函数 return 什么都没有,尽管它的 return 类型不是 void。
int power(int value, int power, int* output) {
还有这个表情
(hex & (powerValue * 15)) / powerValue + '0'
没有意义。
需要启用 SSE 单元才能使用浮点数和双精度数。以及更改值的传回方式。工作代码:
void log(float value, float base, uint64_t* output) {
uint64_t i = 0;
while (value >= 1) {
value /= base;
i++;
}
*output = i;
}
void pow(uint64_t value, uint64_t exponent, uint64_t* output) {
uint64_t result = 1;
for (uint64_t i = 0; i < exponent; i++) {
result = result * value;
}
*output = result;
}
void hexToStr(uint64_t hex, char* output) {
uint8_t hexLen = 16;
log((float)hex, (float)16, &hexLen);
char result[hexLen + 3];
result[0] = '0';
result[1] = 'x';
result[hexLen + 2] = 0;
uint64_t powerValue = 1;
for (uint8_t i = 0; i < hexLen; i++) {
pow(16, i, &powerValue);
result[hexLen - i + 1] = (hex & (uint64_t)(powerValue * (uint64_t)15)) / powerValue + '0';
}
for (uint8_t i = 0; i < hexLen + 3; i++) {
switch(result[i]) {
case ':':
result[i] = 'A';
break;
case ';':
result[i] = 'B';
break;
case '<':
result[i] = 'C';
break;
case '=':
result[i] = 'D';
break;
case '>':
result[i] = 'E';
break;
case '?':
result[i] = 'F';
break;
}
output[i] = result[i];
}
}