我从以下代码开始:
void func1() {
char tmpfile[] = "/tmp/tmpXXXXXX";
mkstemp(tmpfile); // Note: mkstemp modifies the char array, cannot be const
...
}
void func2() {
char tmpfile[] = "/tmp/tmpXXXXXX";
mkstemp(tmpfile); // Note: mkstemp modifies the char array, cannot be const
...
}
我想对其进行重构以提取共享的"/tmp/tmpXXXXXX"
常量。这是一个尝试:
constexpr char kTmpfile[] = "/tmp/tmpXXXXXX";
void func1() {
char tmpfile[] = kTmpfile;
mkstemp(tmpfile); // Note: mkstemp modifies the char array, cannot be const
...
}
void func2() {
char tmpfile[] = kTmpfile;
mkstemp(tmpfile); // Note: mkstemp modifies the char array, cannot be const
...
}
但是,这不能编译。将tmpfile[]
更改为tmpfile[sizeof(kTmpfile)]
也不起作用。
下面的确实有效,但是它使用了我的公司的样式指南(基于Google Style Guide)不建议使用的宏。
#define TMPFILE "/tmp/tmpXXXXXX"
void func1() {
char tmpfile[] = TMPFILE;
mkstemp(tmpfile); // Note: mkstemp modifies the char array, cannot be const
...
}
void func2() {
char tmpfile[] = TMPFILE;
mkstemp(tmpfile); // Note: mkstemp modifies the char array, cannot be const
...
}
有什么办法写得“漂亮”吗?不必使用宏或硬编码大小?还是宏是可读性和可维护性的最佳选择?
答案 0 :(得分:4)
这是三种方法。值得一提的是@πάνταῥεῖ,@ PSkocik和@Asu提出的建议,我只是打了一下。
方法1a
constexpr auto kTmpfile = "/tmp/tmpXXXXXX";
void func1() {
std::string tmpfile = kTmpfile;
mkstemp(tmpfile.data());
...
}
优势:
缺点:
std::string::data
在C ++ 14和更早的版本中返回const char*
(当然,您可以在C ++ 14中使用const_cast
,但这是也不好)方法1b
constexpr auto kTmpfile = "/tmp/tmpXXXXXX";
void func1() {
std::string tmpfile = kTmpfile;
mkstemp(&tmpfile[0]);
...
}
优势:
缺点:
方法2
constexpr char kTmpfile[] = "/tmp/tmpXXXXXX";
void func1() {
char tmpfile[sizeof(kTmpfile)];
memcpy(tmpfile, kTmpfile, sizeof(kTmpfile));
mkstemp(tmpfile);
...
}
优势:
缺点:
答案 1 :(得分:2)
您可以使用std::array
和一些 template magic 来确定数组大小;
$table_query
要获取#include <array>
#include <algorithm>
constexpr char kTmpfile[] = "/tmp/tmpXXXXXX";
template<typename T, size_t N>
constexpr size_t array_size(T(&)[N])
{
return N;
}
void func1() {
std::array<char, array_size(kTmpfile)> var;
std::copy(std::begin(kTmpfile), std::end(kTmpfile), var.begin());
mkstemp(var.data());
//...
}
中的数据,可以调用函数data()
。
答案 2 :(得分:2)
只要char数组是本地的,就可以替换
char tmpfile[] = STR_LITERAL;
与
char tmpfile[sizeof kTmpfile]; memcpy(tmpfile,kTmpfile,sizeof tmpfile);
理论上没有效率损失。
例如,下面的代码片段中的compiles both func1 and func2会在x86_64上变成相同的说明:
#include <stdlib.h>
int func1() {
char tmpfile[] = "/tmp/tmpXXXXXX";
mkstemp(tmpfile);
}
#include <string.h>
const char kTmpfile[] = "/tmp/tmpXXXXXX";
int func2() {
char tmpfile[sizeof kTmpfile];
memcpy(&tmpfile,kTmpfile,sizeof tmpfile);
mkstemp(tmpfile);
}
组装输出:
func1(): # @func1()
subq $24, %rsp
movabsq $24866934413088880, %rax # imm = 0x58585858585870
movq %rax, 15(%rsp)
movabsq $8101259051807896623, %rax # imm = 0x706D742F706D742F
movq %rax, 8(%rsp)
leaq 8(%rsp), %rdi
callq mkstemp
func2(): # @func2()
subq $24, %rsp
movabsq $24866934413088880, %rax # imm = 0x58585858585870
movq %rax, 15(%rsp)
movabsq $8101259051807896623, %rax # imm = 0x706D742F706D742F
movq %rax, 8(%rsp)
leaq 8(%rsp), %rdi
callq mkstemp
这种无需使用宏即可重构重复的初始化字符串的解决方案在纯C语言中也适用。
使用std::string
,尽管它通常会使用堆,这比堆栈要贵很多,但也不会在这里造成太大的损失,因为您可以预期文件创建将至少花费一微秒,并且从而主导了堆分配和字符串复制。
答案 3 :(得分:1)
另一种方法,C ++ 11(如果您编写构造函数,则为C ++ 03):
struct KTmpfile { char value[...] = "/tmp/tmpXXXXXX"; };
void func1() {
KTmpfile tmpfile;
mkstemp(tmpfile.value);
...
}
仅堆栈,func*
用户中可能的最小代码。
请注意,您当然必须指定value
的大小(或重复文字以找出大小)。
在我看来,这是最好的方法,因为您真正想要的是要获取多个实例的类型-您知道其大小和初始值,因此请为其创建一个合适的类型
并且,在这一点上,由于您有一个类型,因此您可以从类型本身(甚至在构造函数中)调用mkstemp
,然后简单地说:
void func1() {
KTmpfile tmpfile;
...
}