byWind's Blog

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

make(3/3):命令与调试技巧

发表于 2019-03-29 | 分类于 基础知识
本文字数: 1.8k | 阅读时长 ≈ 4 分钟

命令

make命令实质上是一个单行shell脚本。实际的执行过程是:make先检查命令中是否有特殊字符(可能影响当前程序的行为),如果没有,就直接执行;如果有,就将其传递给subshell执行(使用fork/exec)。

make命令默认会交给/bin/sh执行,这由SHELL变量指定,出于可移植性的考虑,一般不建议修改。(不过改成bash还是可以接受的)

命令的解析

在工作目标之后,凡是第一个字符是tab的文本一律被视为命令(触发上一行结尾是反斜线)。因此,以tab开头的注释(# …)为shell注释,也会出现在console中。而以空格(无论多少个)开头的注释则为make注释,会被直接忽略。

make可以识别命令末尾的反斜线,已将其视为同一个命令,如:

1
2
3
4
5
6
.INTERMEDIATE: file_list
file_list:
for d in logic ui; \
do \
echo $$d/*.java; \
done > $@

这里补充一点,上一篇中提到过.INTERMEDIATE生成的文件最后会被删除,但是如果运行make file_list,这个规则就不是中间过程,生成的文件也不会被删除。

再举一个cd的例子:

1
2
3
TAGS:
cd src && \
ctags -recurse
阅读全文 »

make(2/3):变量、宏与函数

发表于 2019-03-28 | 更新于 2019-03-29 | 分类于 基础知识
本文字数: 3.7k | 阅读时长 ≈ 9 分钟

变量与宏

变量可以由任意除了:、#、=的字符组成,在访问变量的时候,如果变量名超过一个字母,要用小括号括起来(花括号{}也可以,但不建议用)。

习惯上用大写字母表示用户在命令行上或环境中自定义的常数,用小写字母表示makefile中出现的变量,单词之间都用下划线隔开。

变量的值由赋值符号右边删除前导空格的所有字符组成。和shell一样,没有定义的变量会被解析为空,举一个例子:

1
MAKE_DEPEND := $(CC) -M

假如$(CC)没有被定义,MAKE_DEPENDd的值最终为<space>-M,这里的空格并不会被删除。

赋值类型

类型 解释
:= 简单扩展,扩展后的字面值被存入变量
= 经递归扩展,储存的实际是待扩展的字符串,等到用的时候再执行扩展
?= 条件赋值,只在变量值不存在的时候才执行赋值
+= 附加运算,将文本附加在变量里。var = $(var) sss的写法是错误的,会无限递归,然而使用:=就可以
阅读全文 »

make(1/3):基本语法与规则

发表于 2019-03-27 | 更新于 2019-03-29 | 分类于 基础知识
本文字数: 2.8k | 阅读时长 ≈ 7 分钟

基本语法

Makefile采用top-down的结构,默认会更新最上层的工作目标(all),而下层的工作目标是为了让上层保持在最新状态(如用于删除无用的临时文件的clean工作目标应该放在最下层)。

每条规则的范例如下:

1
2
3
4
target1 target2 target3 : prerequisite1 prerequisite2
command1
command2
command3

说明:

  • 如果不存在prerequisite,只检查target是否存在
  • command前面要有一个tab,不能用空格
  • #表示注释

规则

通配符

makefile中允许使用shell中的~、*、?、[]、[^]等通配符。

假想工作目标

假想工作目标(phony target)指的是不代表文件的工作目标,如all、clean。

如果当前工作目录下存在名为clean的文件,clean工作目标就被降级成普通工作目标了。为了解决这一问题,也为了自定义假想工作目标,我们可以将工作目标指定成PHONY,如

1
2
3
.PHONY: clean
clean:
rm -f *.o lexer.c
阅读全文 »

汉明编码

发表于 2019-03-05 | 分类于 算法分析
本文字数: 617 | 阅读时长 ≈ 2 分钟

汉明编码是一种可用于纠错的编码方式,通过增加很少的冗余位来达到纠正错误的目的。普通的汉明编码具有一位的纠错能力。

例子

最常见的汉明编码是4->7的:也就是说4位的数据+3位的纠错码,总共每次传输7位的数据,如果其中有一位翻转,我们也可以通过校验的方式准确得知是哪一位出错的。

假设待编码的数据是1011,编码过程见下表:

校验位1 校验位2 数据位1 校验位3 数据位2 数据位3 数据位4
校验位1 1^0^1 1 0 1
校验位2 1^1^1 1 1 1
校验位3 0^1^1 0 1 1
结果 0 1 1 0 0 1 1

上表的含义是:校验位1 = 数据位1 ^ 数据位2 ^ 数据位4,依此类推。至于为什么是这样的,后面再讲。

阅读全文 »

[Java]《编写高质量代码》笔记(2/2)

发表于 2019-02-25 | 分类于 基础知识
本文字数: 2k | 阅读时长 ≈ 5 分钟

《编写高质量代码》笔记(1/2)

数组和集合

警惕数组的浅拷贝

通过copyOf的方法得到的数组是一个浅拷贝,而且,数组的clone方法也只能得到浅拷贝。

需要注意的是,集合并没有提供拷贝的方法,这时不要使用诸如List.toArray的方法尝试利用Array的copyOf方法,这样就恰好撞到枪口上了。

在明确场景下,为集合指定初始容量

常用的ArrayList会按照1.5倍的速度扩容,每次扩容都是一次数组的拷贝,如果数据量大,这样的拷贝会非常耗资源。与之类似,Vector默认按照2倍的速度扩容,但是这个速率可以在构造函数中自己指定。

原始类型数组不能作为asList的参数

1
2
int[] data = {1,2,3,4,5};
List list = Arrays.asList(data);

这时list的长度为1,且list[0]为data数组,修改方法如下:

1
2
Integer[] data = {1,2,3,4,5};
List list = Arrays.asList(data);
阅读全文 »

除自身以外数组的乘积

发表于 2019-02-24 | 分类于 算法题
本文字数: 865 | 阅读时长 ≈ 2 分钟

题目

#238 Product of Array Except Self

给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。

进阶:你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)

阅读全文 »

[Java]《编写高质量代码》笔记(1/2)

发表于 2019-02-24 | 分类于 基础知识
本文字数: 1.4k | 阅读时长 ≈ 4 分钟

《编写高质量代码》笔记(2/2)

通用的方法和准则

尽量显示声明UID

在编写一个可序列化的类(implements Serializable)时,尽量要显式声明serialVersionUID。当我们把一个对象序列化后储存或通过网络传输后,若想要将其反序列化,Java会检测其UID是否相同,如果不同,就会抛出InvalidClassException的异常。如果我们不显示指定serialVersionUID,编译器在编译时会根据包名、类名等属性生成一个独一无二的UID,那么当我们的类改变不大,却又想让JVM反序列化时,就遇到麻烦了。显示声明UID可以“骗过”JVM,告诉它我这还是一个类,可以方便地做到向下兼容,当出现巨大改变的时候,我们仍可以手动修改UID。

附: 显式声明的格式

1
private static final long serialVersionUID = XXXXXXXXXL;

在序列化类中,不使用构造函数为final变量赋值

反序列化时构造函数不会执行!!

在发布应用时不要只替换一个类

对于final修饰的基本类型和String类型,编译器会认为它是稳定态,所以在编译时直接把值编译到字节码中了。但这个问题在当前主流的IDE中都不存在,它们都默认编译所有的引用类。

阅读全文 »

记一段神奇的代码

发表于 2019-02-23 | 分类于 算法分析
本文字数: 506 | 阅读时长 ≈ 1 分钟

最近在刷一道leetcode的题的时候发现有个速度排名非常靠前的代码中有这样一段:

1
2
3
4
5
6
7
8
static const auto io_sync_off = []()
{
// turn off sync
std::ios::sync_with_stdio(false);
// untie in/out streams
std::cin.tie(nullptr);
return nullptr;
}();

老实讲,他的算法和我的几乎一样,但是就是因为多了这一段代码,他的执行时间为20ms,而我的为72ms。

在网上查阅资料后得知,这段代码是一个lambda表达式,涉及到输入输出流的缓冲与刷新同步的问题。详细分析可见:解析 static auto x = []() { std::ios::sync_with_stdio(false)\;std::cin.tie(nullptr)\;return 0\;}()

但我仍感觉这类代码意义不大,并不能真正提高解决问题的能力,而是通过加快测试用例的输入与结果的输出速度来欺骗leetcode的评审机制罢了。

阅读全文 »
123…6
Li Hao

Li Hao

46 日志
9 分类
20 标签
GitHub E-Mail
Links
  • Norton
  • lazzy
  • Alevery
  • pdfcxc
0%
© 2019 Li Hao | 95k | 3:58
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Pisces v7.0.1
|