可能重复:
1/0是合法的Java表达式吗?
为什么这段代码会编译?
class Compiles {
public final static int A = 7/0;
public final static int B = 10*3;
public static void main(String[] args) {}
}
Run Code Online (Sandbox Code Playgroud)
如果我查看已编译的类文件,我可以看到B已经被评估为30,而A仍然是7/0.
据我所知,JSL是一个除以零的表达式,它不是常数.
参考:JLS 15.28
我的上述陈述是由于这一行:
编译时常量表达式是表示基本类型值的表达式
因此,除以零不会被评估为原始值.
我真的不明白为什么编译器允许这样做呢?为了清楚起见,上面的代码使用"java.lang.ExceptionInInitializerError"崩溃了运行时
在我看来,编译器威胁任何最终的静态变量作为常量并评估它的编译时间.这意味着编译器已经尝试评估A,但由于它是零除以它只是让它通过.没有编译时错误.但这看起来非常奇怪...编译器知道它是零除以它会崩溃运行时但是它不会标记编译错误!
任何人都可以向我解释原因吗?
java constants compile-time-constant jls constant-expression
随着讨论这里,javac的和其他Java编译器可以提供代码消除能力if-statements这里的条件是"常量表达式".
如果我的代码使用依赖于不同包中定义的其他常量表达式的常量表达式,这会受到什么影响?
例如,假设我在相应的指定包中有以下类:
package foo;
public class Foo {
public static final boolean CONDITION = false;
}
Run Code Online (Sandbox Code Playgroud)
和
package bar;
import foo.Foo;
public class Bar {
public void test() {
if (Foo.CONDITION) {
System.out.println("This line of code could be eliminated.");
} else {
System.out.println("This line of code will be executed.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
显然,如果foo-package是在从外部JAR文件运行时加载,编译器不能在技术上只是假设,Foo.CONDITION将是错误的,不应该消除true的分枝的if语句来.
然而,如果Foo并且Bar实际上在同一个包中,则true应该绝对消除-branch(如果编译器完全支持代码消除).
不太确定如何最好短语这个问题,但:如何"亲密"也Foo必须是Bar常量表达式在 …
java compiler-construction dead-code constant-expression code-elimination
在assert从-macro <cassert>提供了保证条件满足一个简洁的方式.如果参数的计算结果为true,则不会产生任何进一步的影响.但是,在这种情况下,它的调用是否也可以在常量表达式中使用?
我有一个返回double值的Java-Annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DoubleValue {
double value();
}
Run Code Online (Sandbox Code Playgroud)
当我尝试将注释附加到scala类中的字段时,值为negativ,如下所示:
class Test {
@DoubleValue(-0.05)
var a = _
}
Run Code Online (Sandbox Code Playgroud)
我得到一个编译器错误消息:"annotation参数需要是一个常量;找到:0.05.unary_-".我明白我需要一个数字文字而且我查看了Scala语言规范,似乎 - 符号仅用于指数但不用于尾数.有人知道如何使用注释将负值作为运行时信息吗?
谢谢,克林克
请参阅更新以获得更好的问题示例.原始代码有各种各样的问题,使图片混乱:
这个问题为什么我可以在constexpr函数中调用非constexpr函数?提出了以下代码
#include <stdio.h>
constexpr int f()
{
return printf("a side effect!\n");
}
int main()
{
char a[f()];
printf("%zd\n", sizeof a);
}
Run Code Online (Sandbox Code Playgroud)
我回答的是格式不正确但gcc 4.8.2允许它(现场观看).
但是,如果我们使用该-fno-builtin标志gcc生成错误(请参见它):
error: call to non-constexpr function 'int printf(const char*, ...)'
return printf("a side effect!\n");
^
Run Code Online (Sandbox Code Playgroud)
所以它seems是gcc正在考虑的内置版本printf是一个常量表达式.gcc 这里构建的文档但不记录这种情况,其中非constexpr函数的内置可以被认为是常量表达式.
如果确实如此:
1.4 实现合规性第8段说(强调我的):符合条件的实现可能具有扩展(包括其他库函数),前提是它们不会改变任何格式良好的程序的行为.需要实现来诊断使用根据本国际标准格式不正确的扩展的程序.但是,这样做之后,他们就可以编译和执行这样的程序. …
假设我的功能如下:
int test(std::array<char, 8>* data) {
char buffer[data->size() * 2];
[... some code ...]
}
Run Code Online (Sandbox Code Playgroud)
显然,可以在编译时评估缓冲区的大小:数据有一个 constexpr大小为8个元素,8*2 = 16个字节.
然而,编译时-Wall,-pedantic而-std=c++11我得到的臭名昭著的错误:
警告:可变长度数组是C99功能[-Wvla-extension]
我相信它是有道理的:array::size()是constexpr,但它仍然是一种方法,在上面的函数中我们仍然必须取消引用指针,而不是constexpr.
如果我尝试类似的东西:
int test(std::array<char, 8>& data) {
char buffer[data.size() * 2];
[...]
}
Run Code Online (Sandbox Code Playgroud)
gcc (尝试过5.2.0版)似乎很高兴:没有警告.
但是对于clang++(3.5.1),我仍然会收到一个抱怨可变长度数组的警告.
在我的情况下,我不能轻易改变签名test,它必须采取指针.那么......几个问题:
在constexpr上下文中获取std::array 指针大小的最佳/最标准方法是什么?
预期指针与引用的行为有何不同?哪个编译器对警告是正确的,gcc或者clang?
以下代码尝试在两个不同的常量上下文中对字符串文字使用数组索引:
static char x = "abcx"[3];
_Static_assert ("abcx"[3] == 'x', "...");
Run Code Online (Sandbox Code Playgroud)
根据Compiler Explorer的判断,工具供应商之间存在明确的共识,即不允许在第二种情况下执行此操作,因为第二种情况明确要求使用整数常量表达式。但是,它们似乎在第一个上下文方面有所不同,第一个上下文只是初始化程序中使用的算术常数表达式。GCC和Clang是允许这样做的实现而脱颖而出。
就其本身而言,这并不有趣,因为在6.6的第10段中,C11 / C18确实表示“实现可以接受其他形式的常量表达式”。但是,在这种情况下脱颖而出是因为:
GCC和Clang都默默地接受了这一点-pedantic(是的,编译器签发并不意味着代码符合要求)。构建代码很有意义,因为它的含义很简单,但是如果他们认为这不符合要求,我会期望发出警告,并且他们可以识别(他们认为)它是否符合要求,因为...
对于这两个编译器,行为最近都发生了变化 -Clang一直在此之前引发错误,直到3.8,而GCC之前一直在引发错误直到8.0。这些版本分别于2016年和2018年发布。这表明更改是有意的,但我还没有找到详细介绍这两个编译器的发行说明。
行为改变的时机使它看起来像与C18有关,但是6.6的措词似乎没有改变。对整数常量表达式的限制仍然严格(如第二行继续显示错误),第9段的措词似乎与C11中的相同,特别是继续说:“对象的值不应为C。通过使用这些运算符可以访问”(wrt []和朋友)。
通过阅读标准,第一个上下文是否是有效的初始化常量(不包括第10段)?我在哪里可能找到GCC / Clang变更的理由?
即使在经过多次Google搜索之后,我对C语言中的常量表达式有什么不同感到困惑.你能提供一个C的常量表达式的例子吗?
我已经在StackOverflow和多谷歌链接上研究了我的问题,我仍然感到困惑.我认为对我来说最好的事情就是问...
我创建一个简单的命令行计算器.到目前为止,这是我的代码:
const std::string Calculator::SIN("sin");
const std::string Calculator::COS("cos");
const std::string Calculator::TAN("tan");
const std::string Calculator::LOG( "log" );
const std::string Calculator::LOG10( "log10" );
void Calculator::set_command( std::string cmd ) {
for(unsigned i = 0; i < cmd.length(); i++)
{
cmd[i] = tolower(cmd[i]);
}
command = cmd;
}
bool Calculator::is_legal_command() const {
switch(command)
{
case TAN:
case SIN:
case COS:
case LOG:
case LOG10:
return true;
break;
default:
return false;
break;
}
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
Calculator.cpp: In member function 'bool Calculator::is_trig_command() const':
Calculator.cpp: error: switch …Run Code Online (Sandbox Code Playgroud) 标准说:
"一个值为 0 的整数常量表达式,或这样一个转换为 type 的表达式
void*,称为空指针常量.67) 如果将空指针常量转换为指针类型,则保证得到的指针称为空指针比较不等于指向任何对象或函数的指针。”
" 67) 宏 NULL 在 stddef.h(和其他头文件)中定义为空指针常量;见 7.19。 "
来源:ISO/IEC 9899:2018 (C18),第 6.2.3.2/3 节“指针”。
最常见的空指针常量当然是最常见的,0并且(void*) 0被大多数实现用作空指针常量,但作为标准要求 - “值为 0 的整数常量表达式,或这样的表达式转换为类型void*” -空指针常量应也可以是以下任何一种:
1 * 00 * 00 - 025 - 25(-4) + (4)(0 * ((0 * 25) * 3)(0) * (-100)就像他们前面有(void*), fe(void*) (1 * 0) …