使用int参数将float传递给函数(事先未声明)

时间:2017-03-02 07:52:02

标签: c

我已阅读Garbage value when passed float values to the function accepting integer parameters个答案。我的问题更深入一些。我本来也可以问我有50多个声望点。我正在添加我的代码以获得更多说明:

#include <stdio.h>
#include <string.h>

void p2(unsigned int tmp)
{
    printf("From p2: \n");
    printf("tmp = %d ,In hex tmp = %x\n", tmp, tmp);
}

int main()
{
    float fvar = 45.65;

    p1(fvar);
    p2(fvar);
    printf("From main:\n");
    printf("sizeof(int) = %lu, sizeof(float) = %lu\n", sizeof(int),
            sizeof(float));
    unsigned int ui;
    memcpy(&ui, &fvar, sizeof(fvar));
    printf("fvar = %x\n", ui);
    return 0;
}

void p1(unsigned int tmp)
{
    printf("From p1: \n");
    printf("tmp = %d ,In hex tmp = %x\n", tmp, tmp);
}

输出是:

From p1: 
tmp = 1 ,In hex tmp = 1
From p2: 
tmp = 45 ,In hex tmp = 2d
From main:
sizeof(int) = 4, sizeof(float) = 4
fvar = 4236999a8

float值传递给使用int参数预先声明的函数(即p2),可得到正确的结果。当使用未事先声明的函数(即p1)尝试相同时,会给出不正确的值。而且我知道编译器不会为之前未声明的函数假设任何类型或参数的原因。这就是为什么float值在p2的情况下不会被int转换为float的原因。

我的困惑是,在p2的情况下,int值究竟是如何被复制到本地int变量tmp的。

如果是“逐位复制”而不是读取那些位置,则至少应该以十六进制形式产生某些东西(除了1)(如果不是整数)。但是输出显示的情况并非如此。我知道浮动表示是不同的。

p2如何读取浮点数未被复制到的寄存器/堆栈位置?正如simonc在链接问题中所建议的那样?

我已经包含floatpublic class WriteRouteActivity extends AppCompatActivity { private Toolbar tb; private TextView txt_toolbar_title; private Button btnSearchPlaces; private LinearLayout parentLayout, placesCoverLayout; private View popupView; private ImageView imgShowPlaces; private boolean isKeyBoardVisible; private int keyboardHeight; private EditText edtSearchPlaces; private PopupWindow popupWindow; //popupView private TabLayout tabLayout; private FrameLayout frameLayout; //prework private int minusVal; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_write_route); initView(); } private void initView() { //for activity and native back button tb = (Toolbar) findViewById(R.id.nav_toolbar); setSupportActionBar(tb); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowTitleEnabled(false); txt_toolbar_title = (TextView) findViewById(R.id.txt_toolbar); parentLayout = (LinearLayout) findViewById(R.id.layout_parent); placesCoverLayout = (LinearLayout) findViewById(R.id.footer_for_places); imgShowPlaces = (ImageView) findViewById(R.id.img_show_places); edtSearchPlaces =(EditText) findViewById(R.id.edt_search_place); btnSearchPlaces = (Button) findViewById(R.id.btn_search_place); popupView = getLayoutInflater().inflate(R.layout.places_popup, null); tabLayout = (TabLayout) popupView.findViewById(R.id.tab_layout); frameLayout = (FrameLayout) popupView.findViewById(R.id.frame_layout); doWorkForLayotus(); } private void doWorkForLayotus(){ final float popUpheight = getResources().getDimension(R.dimen.keyboard_height); changeKeyboardHeight((int) popUpheight); enablePopUpView(); setTabLayout(); checkKeyboardHeight(parentLayout); enableFooterView(); } public void setCurrentTabFragment(int position) throws IllegalAccessException, InstantiationException { String tag=""; Fragment fr = null; Class frClass = null; FragmentManager frManager = getSupportFragmentManager(); switch (position) { case 0: tag = "first"; //hide if(frManager.findFragmentByTag("second")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("second")).commit(); } if(frManager.findFragmentByTag("third")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("third")).commit(); } if(frManager.findFragmentByTag("fourth")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("fourth")).commit(); } //show if(frManager.findFragmentByTag("first")!=null){ frManager.beginTransaction().show(frManager.findFragmentByTag("first")).commit(); }else{ //add try { frManager.beginTransaction().add(frameLayout.getId(), ((Fragment) Fragment_zasin.class.newInstance()), tag).commit(); }catch(Exception e){ Log.e("why", e.getMessage().toString()); } } break; case 1: tag = "second"; //hide if(frManager.findFragmentByTag("first")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("first")).commit(); } if(frManager.findFragmentByTag("third")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("third")).commit(); } if(frManager.findFragmentByTag("fourth")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("fourth")).commit(); } //show if(frManager.findFragmentByTag("second")!=null){ frManager.beginTransaction().show(frManager.findFragmentByTag("second")).commit(); }else{ //add frManager.beginTransaction().add(frameLayout.getId(), ((Fragment) Fragment_zasin.class.newInstance()), tag).commit(); } break; case 2: tag = "third"; //hide if(frManager.findFragmentByTag("first")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("first")).commit(); } if(frManager.findFragmentByTag("second")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("second")).commit(); } if(frManager.findFragmentByTag("fourth")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("fourth")).commit(); } //show if(frManager.findFragmentByTag("third")!=null){ frManager.beginTransaction().show(frManager.findFragmentByTag("third")).commit(); }else{ //add frManager.beginTransaction().add(frameLayout.getId(), ((Fragment) Fragment_zasin.class.newInstance()), tag).commit(); } break; case 3: tag = "fourth"; //hide if(frManager.findFragmentByTag("first")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("first")).commit(); } if(frManager.findFragmentByTag("second")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("second")).commit(); } if(frManager.findFramentByTag("third")!=null){ frManager.beginTransaction().hide(frManager.findFragmentByTag("third")).commit(); } //show if(frManager.findFragmentByTag("fourth")!=null){ frManager.beginTransaction().show(frManager.findFragmentByTag("fourth")).commit(); }else{ //add frManager.beginTransaction().add(R.id.frame_layout, ((Fragment) Fragment_zasin.class.newInstance()), tag).commit(); } break; } //frManager.beginTransaction().replace(R.id.frame_container, fr, tag).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit(); } private void setTabLayout(){ tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { try { setCurrentTabFragment(tab.getPosition()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); } private void enablePopUpView() { // Creating a pop window for emoticons keyboard popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, (int) keyboardHeight, false); popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { placesCoverLayout.setVisibility(LinearLayout.GONE); } }); } int previousHeightDiffrence = 0; private void checkKeyboardHeight(final View parentLayout) { parentLayout.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); parentLayout.getWindowVisibleDisplayFrame(r); int screenHeight = parentLayout.getRootView() .getHeight(); minusVal=screenHeight-r.bottom; int heightDifference = screenHeight - (r.bottom+(minusVal)); if (previousHeightDiffrence - heightDifference > 50) { popupWindow.dismiss(); } previousHeightDiffrence = heightDifference; if (heightDifference > 100) { isKeyBoardVisible = true; changeKeyboardHeight(heightDifference); } else { isKeyBoardVisible = false; } } }); } private void changeKeyboardHeight(int height) { if (height > 100) { keyboardHeight = height; LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, keyboardHeight); placesCoverLayout.setLayoutParams(params); } } private void enableFooterView() { edtSearchPlaces.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (popupWindow.isShowing()) { popupWindow.dismiss(); } } }); btnSearchPlaces.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { hideSoftKeyboard(WriteRouteActivity.this); if(!popupWindow.isShowing()){ popupWindow.setHeight((int) (keyboardHeight)); if (isKeyBoardVisible) { placesCoverLayout.setVisibility(LinearLayout.GONE); } else { placesCoverLayout.setVisibility(LinearLayout.VISIBLE); } popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED); popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); popupWindow.showAtLocation(parentLayout, Gravity.BOTTOM, 0, 0); try { setCurrentTabFragment(0); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } else { //popupWindow.dismiss(); } } }); } @Override protected void onDestroy() { popupWindow.dismiss(); super.onDestroy(); } public static void hideSoftKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService( Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( activity.getCurrentFocus().getWindowToken(), 0); } @Override public void onBackPressed() { if(popupWindow.isShowing()){ popupWindow.dismiss(); }else { super.onBackPressed(); } } } 两者的大小,如果有帮助,我的编译器就是gcc。

3 个答案:

答案 0 :(得分:3)

C编程语言本质上是一种单扫描语言 - 编译器不需要重新读取代码,但它可以逐行汇编,只保留有关如何声明标识符的信息。

C89标准具有隐式声明的概念。如果没有声明,函数p1将隐式声明为int p1();即一个返回int的函数,并接受通过默认参数提升的未指定参数。当你调用这样一个函数给它一个float作为参数时,float参数会被提升为double,这是默认参数提升所要求的。如果函数是int p1(double arg),那就没关系了。但是预期的参数类型是unsigned int,并且返回值也不兼容(void vs int)。这种不匹配将导致程序具有未定义的行为 - 没有必要在推理当时发生的事情。但是,如果编译器不支持古老的隐式声明,那么许多旧的C程序将无法编译 - 因此您只需将所有这些警告视为错误。

请注意,如果您将p1返回值更改为 int ,则会收到更少的警告:

% gcc implicit.c
implicit.c:14:5: warning: implicit declaration of function ‘p1’ [-Wimplicit-function-declaration]
 p1(fvar);
 ^~

但我在编译器上观察到的行为大致相同。

因此,仅存在警告:隐式声明函数'x'很可能是新编写的代码中的严重错误

如果在使用之前声明了函数,就像p2的情况一样,那么编译器知道它期望unsigned long作为参数,并返回void,因此它会知道为参数生成从floatunsigned long的正确转换代码。

C99和C11在严格一致的程序中不允许隐式函数声明 - 但它们也不需要符合标准的编译器来拒绝它们。 C11说:

  

标识符是主表达式,前提是它已被声明为指定对象(在这种情况下它是左值)或函数(在这种情况下它是函数指示符)。

和脚注,注意到

  

因此,未声明的标识符违反了语法。

但是,它并不需要编译器拒绝它们。

答案 1 :(得分:2)

此,

 SupportPlaceAutocompleteFragment autocompleteFragment = (SupportPlaceAutocompleteFragment) getSupportFragmentManager().findFragmentById(R.id.place_autocomplete_fragment);

implicitly declared作为

void p1(unsigned int tmp);

由编译器。

虽然编译器没有抛出错误,但应该将其视为一个,因为您可以在链接的帖子中阅读。

无论如何,这是未定义的行为,您不能指望可预测的输出。

答案 2 :(得分:0)

在二进制级别,floatint看起来并不相同。

尝试将float复制到int时,会出现隐式转换,这就是为什么当您调用以int为参数的函数时但是你提供了float你得到它的整数部分,但是在最后的测试中你会看到它看起来有多丑。这不是垃圾,如果你用十六进制打印它,float在内存中的样子。有关详细信息,请参阅IEEE 754

p1()的问题是,您正在尝试调用尚未声明的函数,因此它会自动声明为int p1()。即使您稍后将其定义为void p1(unsigned int tmp),它也已被声明为int p1()(不接受任何参数),因此它不起作用(行为未定义)。我很确定编译器会因为警告和错误而尖叫,这些错误并不意味着被忽略。

请注意,声明和定义函数之间存在很大差异。在以后的方式定义函数是完全合法的,但是如果你想让它正常工作,必须在任何尝试使用它之前声明它。

示例:

// declare functions
void p1(unsigned int tmp);
void p2(unsigned int tmp);

// use functions
int main()
{
    p1(1);
    p2(1);
}

// define functions
void p1(unsigned int tmp)
{
    // do stuff
}
void p2(unsigned int tmp)
{
    // do stuff
}