【发布时间】:2021-05-23 02:49:20
【问题描述】:
我正在开发一组函数模板并且编译得很好。您可以在 Compiler Explorer 上看到它们在 here 上工作...问题是当我尝试在我的项目中将它与 T = float 一起使用时,由于多个定义而无法链接...我尝试了各种事情和似乎无法解决这个问题...
这是我的头文件:
cstr.h
#pragma once
#include <stdint.h>
const uint8_t default_decimal_places = 8;
template<typename T>
const char* to_string(T value) {
static char output_buffer[128];
uint8_t negative = 0;
bool isNegative = false;
if (value < 0) {
isNegative = true;
negative = 1;
value *= -1;
output_buffer[0] = '-';
}
uint8_t size = 0;
T sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
if (isNegative) {
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_buffer[negative + size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_buffer[negative + size - idx] = remainder + '0';
output_buffer[negative + size + 1] = 0;
}
else {
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_buffer[size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_buffer[size - idx] = remainder + '0';
output_buffer[size + 1] = 0;
}
return output_buffer;
}
template<typename T>
const char* to_string(T value, uint8_t decimal_places) {
if (decimal_places > 20) decimal_places = 20;
static char output_double_buffer[128];
char* intPtr = (char*)to_string((int64_t)value);
char* doublePtr = output_double_buffer;
if (value < 0) {
value *= -1;
}
while(*intPtr != 0) {
*doublePtr = *intPtr;
intPtr++;
doublePtr++;
}
*doublePtr = '.';
doublePtr++;
T newValue = value - (int)value;
for (uint8_t i = 0; i < decimal_places; i++) {
newValue *= 10;
*doublePtr = (int)newValue + '0';
newValue -= (int)newValue;
doublePtr++;
}
*doublePtr = 0;
return output_double_buffer;
}
template<>
inline const char* to_string<float>(float value, uint8_t decimal_places) {
if (decimal_places > 14) decimal_places = 14;
static char output_float_buffer[128];
char* intPtr = (char*)to_string((int64_t)value);
char* floatPtr = output_float_buffer;
if (value < 0) {
value *= -1;
}
while(*intPtr != 0) {
*floatPtr = *intPtr;
intPtr++;
floatPtr++;
}
*floatPtr = '.';
floatPtr++;
float newValue = value - (int)value;
for (uint8_t i = 0; i < decimal_places; i++) {
newValue *= 10;
*floatPtr = (int)newValue + '0';
newValue -= (int)newValue;
floatPtr++;
}
*floatPtr = 'f';
floatPtr++;
*floatPtr = 0;
return output_float_buffer;
}
它是 cpp 文件...
#include "cstr.h"
调用它们的类...
BasicRenderer.cpp
void BasicRenderer::Print(double val, uint8_t decimal_places) {
Print(to_string(val, decimal_places));
}
void BasicRenderer::Print(float val, uint8_t decimal_places) {
Print(to_string(val, decimal_places));
}
但是,当我在我的应用程序中运行它时... GCC 给了我这个链接器错误...
skilz420@skilz-PC:~/skilzOS/kernel$ make kernel
!==== COMPILING src/cstr.cpp
gcc -ffreestanding -fshort-wchar -c src/cstr.cpp -o lib/cstr.o
!==== LINKING
ld -T kernel.ld -static -Bsymbolic -nostdlib -o bin/kernel.elf lib/kernel.o lib/cstr.o lib/BasicRenderer.o
ld: lib/BasicRenderer.o: in function `char const* to_string<float>(float, unsigned char)':
BasicRenderer.cpp:(.text+0x0): multiple definition of `char const* to_string<float>(float, unsigned char)'; lib/kernel.o:kernel.cpp:(.text+0x0): first defined here
make: *** [Makefile:33: link] Error 1
skilz420@skilz-PC:~/skilzOS/kernel$
我什至尝试将它的定义移动到CPP 文件中,将其内联,等等......这是一个漫长的夜晚,我只想在我称之为夜晚之前让它工作......double本身工作正常,但是当我尝试添加并专门化 float 变体时会这样做,是的,float 的行为与 double 不同。
【问题讨论】:
-
您可以考虑使用不同的名称,例如
to_cstring,以避免与返回std::string的std::to_string发生冲突。另外,我猜这些是为了“立即”使用,因为返回的指针指向一个static局部变量,但是您是否考虑过更类似于std::to_chars的接口? -
@Bob__ 我实际上正在关注一个视频系列,并且我正在接近视频中的实现......在他们开始为每种类型编写相同的函数之后......我只是试过模板化这些函数......使用这些函数的 Print 函数现在实际上属于一个类......所以不应该与
stl函数发生“冲突”。到目前为止,我没有在使用它们的类集之外使用这些函数,我们也没有使用stl,因为它是从头开始编写自定义操作系统的系列...... -
@super 是的,我忘了添加调用这些的类函数......我离开电脑,喝了一杯然后回来......然后我意识到了什么导致链接错误...您可以从我下面的回答中看到。
-
@super 我还添加了调用这些函数模板的函数,它们处于我能够修复它们之前的状态......
标签: c++ templates gcc linker-errors multiple-definition-error